@topmindspace/tms-skills 0.3.5 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +88 -1
  2. package/README.en.md +4 -4
  3. package/README.md +4 -4
  4. package/bin/tms-skills.js +9 -1
  5. package/package.json +1 -1
  6. package/top-ppt-html/README.en.md +2 -2
  7. package/top-ppt-html/README.md +1 -1
  8. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.html +43 -14
  9. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.html +43 -14
  10. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.html +43 -14
  11. package/top-ppt-html/assets/examples/2026-09-26-topmind-tms-skills-showcase.html +43 -14
  12. package/top-ppt-html/assets/pptx-export.js +42 -13
  13. package/top-ppt-html/assets/style-gallery.html +1 -1
  14. package/top-ppt-html/assets/templates/architecture.html +45 -15
  15. package/top-ppt-html/assets/templates/presentation.html +45 -15
  16. package/top-ppt-html/assets/templates/research.html +45 -15
  17. package/top-ppt-html/scripts/audit_css.py +1 -1
  18. package/top-ppt-html/scripts/build_pptx.js +136 -25
  19. package/top-ppt-html/scripts/layout-constants.json +1 -1
  20. package/top-ppt-html/scripts/regression.py +3 -3
  21. package/top-ppt-html/scripts/render_compare.py +1 -1
  22. package/top-ppt-html/scripts/scaffold_report.py +1 -1
  23. package/top-ppt-html/scripts/sync_runtime.py +14 -14
  24. package/top-ppt-html/scripts/validate_report.py +4 -0
  25. package/topmind-cover/README.en.md +8 -9
  26. package/topmind-cover/README.md +8 -9
  27. package/topmind-cover/SKILL.md +28 -8
  28. package/topmind-cover/assets/examples/README.md +2 -2
  29. package/topmind-cover/assets/examples/big-type-wechat.png +0 -0
  30. package/topmind-cover/assets/examples/big-type.png +0 -0
  31. package/topmind-cover/assets/examples/brand-launch-wechat.png +0 -0
  32. package/topmind-cover/assets/examples/brand-launch.png +0 -0
  33. package/topmind-cover/assets/examples/gan-huo-wechat.png +0 -0
  34. package/topmind-cover/assets/examples/gan-huo.png +0 -0
  35. package/topmind-cover/assets/examples/ip-fun-wechat.png +0 -0
  36. package/topmind-cover/assets/examples/ip-fun.png +0 -0
  37. package/topmind-cover/assets/examples/magazine-wechat.png +0 -0
  38. package/topmind-cover/assets/examples/magazine.png +0 -0
  39. package/topmind-cover/assets/examples/minimal-wechat.png +0 -0
  40. package/topmind-cover/assets/examples/minimal.png +0 -0
  41. package/topmind-cover/assets/examples/news-flash-wechat.png +0 -0
  42. package/topmind-cover/assets/examples/news-flash.png +0 -0
  43. package/topmind-cover/assets/examples/overview.png +0 -0
  44. package/topmind-cover/assets/examples/tutorial-steps-wechat.png +0 -0
  45. package/topmind-cover/assets/examples/tutorial-steps.png +0 -0
  46. package/topmind-cover/references/cover-styles.md +160 -172
  47. package/topmind-cover/references/impact-language.md +91 -0
  48. package/topmind-cover/scripts/crop-cover.py +19 -13
  49. package/topmind-wechat-post/README.en.md +2 -2
  50. package/topmind-wechat-post/README.md +2 -2
  51. package/topmind-wechat-post/SKILL.md +1 -1
  52. package/topmind-wechat-post/scripts/md2wechat.py +12 -3
  53. package/topmind-x-article/README.en.md +1 -1
  54. package/topmind-x-article/README.md +1 -1
  55. package/topmind-x-article/scripts/md2x.py +7 -2
@@ -1180,6 +1180,8 @@ font-weight:600}
1180
1180
  </div>
1181
1181
  </section>
1182
1182
 
1183
+ <!-- __TOPPPT_CONTENT_END__ -->
1184
+
1183
1185
  <!-- ══ 页脚 ══ -->
1184
1186
  <footer class="foot">
1185
1187
  <div class="wrap foot__in">
@@ -1193,7 +1195,6 @@ font-weight:600}
1193
1195
  <div class="t-xs">密级说明</div>
1194
1196
  </div>
1195
1197
  </footer>
1196
- <!-- __TOPPPT_CONTENT_END__ -->
1197
1198
 
1198
1199
  <!-- ══ 页码指示(翻页导航) ══ -->
1199
1200
  <aside class="pager" id="pager" aria-label="页码导航">
@@ -1818,7 +1819,7 @@ window.REPORT_MODEL = {
1818
1819
 
1819
1820
  /* __TOPPPT_RUNTIME_START__ */
1820
1821
  /* ══ PPTX 导出运行时(assets/pptx-export.js 的内联副本 · 由 scripts/sync_runtime.py 注入,禁止手改) ══ */
1821
- /* __TOPPPT_RUNTIME_SHA__:af6e25f25fd2e116 */
1822
+ /* __TOPPPT_RUNTIME_SHA__:a4c909346759fe9c */
1822
1823
  /* ═══════════════════════════════════════════════════════════════════════════
1823
1824
  * TopPPT HTML· 浏览器端 PPTX 预览运行时
1824
1825
  * 零依赖、随报告单文件分发;OOXML 序列化器(仅供预览,页面不导出文件)。
@@ -1873,7 +1874,7 @@ function isRec(v) { return !!v && typeof v === 'object' && !Array.isArray(v); }
1873
1874
  var PW = 13.333, PH = 7.5, MX = 0.6, CW = PW - 2 * MX, EMU = 914400;
1874
1875
  var TS_BASE = {"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10};
1875
1876
  var MTS = {"presentation":{"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10},"research":{"coverTitle":36,"coverSub":14,"h1":22,"h2":13.5,"lead":11.5,"body":10.5,"caption":9,"micro":8.5},"architecture":{"coverTitle":44,"coverSub":19,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10}};
1876
- var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":5.3,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
1877
+ var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":10.8,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
1877
1878
  var PRESETS = {
1878
1879
  'business-blue': { accent:'1A73E8', ink:'202124', body:'5F6368', faint:'80868B', bg:'FFFFFF', surface:'F8F9FA', line:'DADCE0', soft:'E8F0FE', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
1879
1880
  'apple-mono': { accent:'1D1D1F', ink:'1D1D1F', body:'6E6E73', faint:'86868B', bg:'FFFFFF', surface:'F5F5F7', line:'D2D2D7', soft:'F5F5F7', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
@@ -2814,7 +2815,9 @@ function infoTableRows(sec) {
2814
2815
  if (t === 'marimekko') {
2815
2816
  var head = ['列', '总量' + u].concat((sec.legend || []).map(String));
2816
2817
  return [head].concat((sec.cols || []).map(function (c, i) {
2817
- return [String(c[0]), String(c[1])].concat(((sec.cells || [])[i] || []).map(String));
2818
+ return [String(c[0]), String(c[1])].concat((((sec.cells || [])[i] || []).map(function (el) {
2819
+ return Array.isArray(el) ? String(el[0]) + ' ' + el[1] : String(el);
2820
+ })));
2818
2821
  }));
2819
2822
  }
2820
2823
  if (t === 'streamgraph') {
@@ -2962,7 +2965,11 @@ function infoApprox(sh, sec, S, y0, y1) {
2962
2965
  var cx1 = MX;
2963
2966
  cols.forEach(function (c, i) {
2964
2967
  var cw = Math.max(0.2, (Number(c[1]) || 0) / total * availW);
2965
- var shares = ((sec.cells || [])[i] || []).map(Number);
2968
+ /* 单元格兼容 [标签,数值] 对(与 B 通道 marimekkoSegs 同规则);非数值 → 0 */
2969
+ var shares = ((sec.cells || [])[i] || []).map(function (el) {
2970
+ var v = Number(Array.isArray(el) ? el[1] : el);
2971
+ return isFinite(v) ? v : 0;
2972
+ });
2966
2973
  var sum = shares.reduce(function (a, b) { return a + b; }, 0) || 1;
2967
2974
  var cy = P.y0;
2968
2975
  shares.forEach(function (v, k) {
@@ -3112,13 +3119,20 @@ function slidesOf(model, S) {
3112
3119
  });
3113
3120
  }
3114
3121
 
3115
- /* 章节页 */
3122
+ /* Exhibit 徽标文本:纯编号补 "Exhibit " 前缀(HTML 为 `Exhibit {no}` + CSS uppercase);
3123
+ 调用方已带前缀的不重复(与 B 通道 exhibitBadge 同规则) */
3124
+ function exhibitBadge(no) {
3125
+ var t = String(no == null ? '' : no).trim();
3126
+ if (!t) return t;
3127
+ return /^exhibit[\s\-:]*/i.test(t) ? t.toUpperCase() : ('EXHIBIT ' + t.toUpperCase());
3128
+ }
3129
+ /* 章节页 */
3116
3130
  (model.sections || []).forEach(function (sec) {
3117
3131
  var type = sec.type || 'points';
3118
3132
  var sh = [];
3119
3133
  if (type !== 'quote') head(sh, sec.eyebrow, sec.title, sec.lead);
3120
3134
  /* 非 exhibit 页型也可带 Exhibit 编号(帧头徽标;正文区下移让位,与 B 通道同规则) */
3121
- var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? String(sec.exhibitNo).toUpperCase() : null;
3135
+ var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? exhibitBadge(sec.exhibitNo) : null;
3122
3136
  var bodyY0 = sec.lead ? PT.common.bodyYWithLead : CONTENT_TOP;
3123
3137
  var bodyY = exBadge ? bodyY0 + 0.42 : bodyY0;
3124
3138
  if (exBadge) {
@@ -3129,7 +3143,7 @@ function slidesOf(model, S) {
3129
3143
  var _F = PT.flagbar || { hdH: 0.26, rowH: 0.24, maxRows: 3, gap: 0.12 };
3130
3144
  var flagH = flagItems.length
3131
3145
  ? (_F.hdH + Math.min(_F.maxRows, flagItems.length) * _F.rowH + 0.06) : 0;
3132
- var bodyBottom = chartBottom(!!sec.soWhat, !!sec.footnote);
3146
+ var bodyBottom = chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note));
3133
3147
  var flagY = 0;
3134
3148
  if (flagH) {
3135
3149
  flagY = CONTENT_BOTTOM - flagH;
@@ -3163,9 +3177,14 @@ function slidesOf(model, S) {
3163
3177
  sh.push(shape('rect', kdivX, K.heroY + 0.15, 0.025, 3.1, S.line));
3164
3178
  var mRegK = regOf('kpi', 'metrics') || { x: kdivX + 0.35, y: K.metricY0, w: CW * (1 - K.dividerX) - 0.5 };
3165
3179
  var kmets = sec.metrics || [];
3166
- var kCap = Math.max(1, Math.floor((CONTENT_BOTTOM - mRegK.y) / K.metricRowH));
3180
+ /* 容量按最小允许行高判断,行高按全部指标自适应压缩 —— 禁静默丢数据(与 B 通道同规则) */
3181
+ var kAvailA = CONTENT_BOTTOM - mRegK.y;
3182
+ var kCap = Math.max(1, Math.floor(kAvailA / 0.42));
3167
3183
  var kRows = Math.min(kmets.length, kCap);
3168
- var kRowH = fitRowH(CONTENT_BOTTOM - mRegK.y, kRows, K.metricRowH, 0.42);
3184
+ if (kRows < kmets.length && typeof console !== 'undefined')
3185
+ console.warn('[pptx-export] KPI 页「' + (sec.title || '') + '」支撑指标 ' + kmets.length +
3186
+ ' 个超出容量,仅渲染前 ' + kRows + ' 个 —— 建议拆页');
3187
+ var kRowH = fitRowH(kAvailA, kRows, K.metricRowH, 0.42);
3169
3188
  var kTopH = Math.min(0.55, kRowH * 0.62);
3170
3189
  kmets.slice(0, kRows).forEach(function (m, i) {
3171
3190
  var ky = mRegK.y + i * kRowH;
@@ -3316,9 +3335,20 @@ function slidesOf(model, S) {
3316
3335
  var lt = isRec(l) ? (l.t || '') : String(l[0] || '');
3317
3336
  var ld = isRec(l) ? (l.d || '') : String(l[1] || '');
3318
3337
  sh.push(shape('roundRect', x2, y2, w2, rowHP, acc ? S.soft : S.surface, { adj: 5000, line: acc ? undefined : S.line }));
3319
- var lwP = Math.min(P.labelW, w2 - 0.44);
3320
- sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3321
- if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, w2 - 0.44 - lwP, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3338
+ var lwP = Math.min(P.labelW, (w2 - 0.44) * (P.labelFrac == null ? 0.32 : P.labelFrac));
3339
+ var descW = w2 - 0.44 - lwP;
3340
+ /* 窄层判定:说明列 < 1.2in,或标题在标题列内放不下单行 → 单框混排(与 B 通道同规则) */
3341
+ var narrowP = descW < 1.2 || (ld && estLines(lt, lwP, 13.5) > 1) || (!ld && estLines(lt, w2 - 0.44, 13.5) > 1);
3342
+ if (narrowP) {
3343
+ /* 顶层窄 → 标题上、说明下单框混排(HTML 窄屏 .pyr__lvl 即单列,与 B 通道同规则) */
3344
+ sh.push(txSp(x2 + 0.22, y2 + 0.03, w2 - 0.44, 0.30,
3345
+ [[{ t: lt, sz: 12.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]]));
3346
+ sh.push(txSp(x2 + 0.22, y2 + 0.33, w2 - 0.44, Math.max(0.2, rowHP - 0.36),
3347
+ [[{ t: ld, sz: 10.5, col: S.faint, font: S.font }]]));
3348
+ } else {
3349
+ sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3350
+ if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, descW, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3351
+ }
3322
3352
  });
3323
3353
  } else if (type === 'steps') {
3324
3354
  var S2 = PT.steps, st = sec.steps || [], maxPer = S2.maxPerRow || 6, groups = sec.groups || [];
@@ -3667,12 +3697,12 @@ function slidesOf(model, S) {
3667
3697
  var eReg = regOf('exhibit', 'primary')
3668
3698
  || { x: MX, y: PT.exhibit.chartY, w: CW, badgeY: PT.exhibit.badgeY };
3669
3699
  if (sec.exhibitNo) {
3670
- sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: String(sec.exhibitNo).toUpperCase(), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3700
+ sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: exhibitBadge(sec.exhibitNo), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3671
3701
  }
3672
3702
  var ec2 = sec.chart || {};
3673
3703
  if (ec2.labels && ec2.values) {
3674
3704
  var edcols2 = (ec2.colors || dataColors(model.style, model.theme));
3675
- var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!sec.footnote) - eReg.y - 0.05);
3705
+ var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note)) - eReg.y - 0.05);
3676
3706
  if (ec2.type === 'hbar') {
3677
3707
  chartBlockShapes(sh, ec2, S, eReg.x, eReg.y, eReg.w, hh2, edcols2);
3678
3708
  } else {
@@ -1184,6 +1184,8 @@ background:var(--surface-2);border-radius:6px;padding:2px 7px;color:var(--text)}
1184
1184
  </div>
1185
1185
  </section>
1186
1186
 
1187
+ <!-- __TOPPPT_CONTENT_END__ -->
1188
+
1187
1189
  <!-- ══ 页脚 ══ -->
1188
1190
  <footer class="foot">
1189
1191
  <div class="wrap foot__in">
@@ -1197,7 +1199,6 @@ background:var(--surface-2);border-radius:6px;padding:2px 7px;color:var(--text)}
1197
1199
  <div class="t-xs">密级说明</div>
1198
1200
  </div>
1199
1201
  </footer>
1200
- <!-- __TOPPPT_CONTENT_END__ -->
1201
1202
 
1202
1203
  <!-- ══ 页码指示(翻页导航) ══ -->
1203
1204
  <aside class="pager" id="pager" aria-label="页码导航">
@@ -1826,7 +1827,7 @@ window.REPORT_MODEL = {
1826
1827
 
1827
1828
  /* __TOPPPT_RUNTIME_START__ */
1828
1829
  /* ══ PPTX 导出运行时(assets/pptx-export.js 的内联副本 · 由 scripts/sync_runtime.py 注入,禁止手改) ══ */
1829
- /* __TOPPPT_RUNTIME_SHA__:af6e25f25fd2e116 */
1830
+ /* __TOPPPT_RUNTIME_SHA__:a4c909346759fe9c */
1830
1831
  /* ═══════════════════════════════════════════════════════════════════════════
1831
1832
  * TopPPT HTML· 浏览器端 PPTX 预览运行时
1832
1833
  * 零依赖、随报告单文件分发;OOXML 序列化器(仅供预览,页面不导出文件)。
@@ -1881,7 +1882,7 @@ function isRec(v) { return !!v && typeof v === 'object' && !Array.isArray(v); }
1881
1882
  var PW = 13.333, PH = 7.5, MX = 0.6, CW = PW - 2 * MX, EMU = 914400;
1882
1883
  var TS_BASE = {"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10};
1883
1884
  var MTS = {"presentation":{"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10},"research":{"coverTitle":36,"coverSub":14,"h1":22,"h2":13.5,"lead":11.5,"body":10.5,"caption":9,"micro":8.5},"architecture":{"coverTitle":44,"coverSub":19,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10}};
1884
- var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":5.3,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
1885
+ var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":10.8,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
1885
1886
  var PRESETS = {
1886
1887
  'business-blue': { accent:'1A73E8', ink:'202124', body:'5F6368', faint:'80868B', bg:'FFFFFF', surface:'F8F9FA', line:'DADCE0', soft:'E8F0FE', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
1887
1888
  'apple-mono': { accent:'1D1D1F', ink:'1D1D1F', body:'6E6E73', faint:'86868B', bg:'FFFFFF', surface:'F5F5F7', line:'D2D2D7', soft:'F5F5F7', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
@@ -2822,7 +2823,9 @@ function infoTableRows(sec) {
2822
2823
  if (t === 'marimekko') {
2823
2824
  var head = ['列', '总量' + u].concat((sec.legend || []).map(String));
2824
2825
  return [head].concat((sec.cols || []).map(function (c, i) {
2825
- return [String(c[0]), String(c[1])].concat(((sec.cells || [])[i] || []).map(String));
2826
+ return [String(c[0]), String(c[1])].concat((((sec.cells || [])[i] || []).map(function (el) {
2827
+ return Array.isArray(el) ? String(el[0]) + ' ' + el[1] : String(el);
2828
+ })));
2826
2829
  }));
2827
2830
  }
2828
2831
  if (t === 'streamgraph') {
@@ -2970,7 +2973,11 @@ function infoApprox(sh, sec, S, y0, y1) {
2970
2973
  var cx1 = MX;
2971
2974
  cols.forEach(function (c, i) {
2972
2975
  var cw = Math.max(0.2, (Number(c[1]) || 0) / total * availW);
2973
- var shares = ((sec.cells || [])[i] || []).map(Number);
2976
+ /* 单元格兼容 [标签,数值] 对(与 B 通道 marimekkoSegs 同规则);非数值 → 0 */
2977
+ var shares = ((sec.cells || [])[i] || []).map(function (el) {
2978
+ var v = Number(Array.isArray(el) ? el[1] : el);
2979
+ return isFinite(v) ? v : 0;
2980
+ });
2974
2981
  var sum = shares.reduce(function (a, b) { return a + b; }, 0) || 1;
2975
2982
  var cy = P.y0;
2976
2983
  shares.forEach(function (v, k) {
@@ -3120,13 +3127,20 @@ function slidesOf(model, S) {
3120
3127
  });
3121
3128
  }
3122
3129
 
3123
- /* 章节页 */
3130
+ /* Exhibit 徽标文本:纯编号补 "Exhibit " 前缀(HTML 为 `Exhibit {no}` + CSS uppercase);
3131
+ 调用方已带前缀的不重复(与 B 通道 exhibitBadge 同规则) */
3132
+ function exhibitBadge(no) {
3133
+ var t = String(no == null ? '' : no).trim();
3134
+ if (!t) return t;
3135
+ return /^exhibit[\s\-:]*/i.test(t) ? t.toUpperCase() : ('EXHIBIT ' + t.toUpperCase());
3136
+ }
3137
+ /* 章节页 */
3124
3138
  (model.sections || []).forEach(function (sec) {
3125
3139
  var type = sec.type || 'points';
3126
3140
  var sh = [];
3127
3141
  if (type !== 'quote') head(sh, sec.eyebrow, sec.title, sec.lead);
3128
3142
  /* 非 exhibit 页型也可带 Exhibit 编号(帧头徽标;正文区下移让位,与 B 通道同规则) */
3129
- var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? String(sec.exhibitNo).toUpperCase() : null;
3143
+ var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? exhibitBadge(sec.exhibitNo) : null;
3130
3144
  var bodyY0 = sec.lead ? PT.common.bodyYWithLead : CONTENT_TOP;
3131
3145
  var bodyY = exBadge ? bodyY0 + 0.42 : bodyY0;
3132
3146
  if (exBadge) {
@@ -3137,7 +3151,7 @@ function slidesOf(model, S) {
3137
3151
  var _F = PT.flagbar || { hdH: 0.26, rowH: 0.24, maxRows: 3, gap: 0.12 };
3138
3152
  var flagH = flagItems.length
3139
3153
  ? (_F.hdH + Math.min(_F.maxRows, flagItems.length) * _F.rowH + 0.06) : 0;
3140
- var bodyBottom = chartBottom(!!sec.soWhat, !!sec.footnote);
3154
+ var bodyBottom = chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note));
3141
3155
  var flagY = 0;
3142
3156
  if (flagH) {
3143
3157
  flagY = CONTENT_BOTTOM - flagH;
@@ -3171,9 +3185,14 @@ function slidesOf(model, S) {
3171
3185
  sh.push(shape('rect', kdivX, K.heroY + 0.15, 0.025, 3.1, S.line));
3172
3186
  var mRegK = regOf('kpi', 'metrics') || { x: kdivX + 0.35, y: K.metricY0, w: CW * (1 - K.dividerX) - 0.5 };
3173
3187
  var kmets = sec.metrics || [];
3174
- var kCap = Math.max(1, Math.floor((CONTENT_BOTTOM - mRegK.y) / K.metricRowH));
3188
+ /* 容量按最小允许行高判断,行高按全部指标自适应压缩 —— 禁静默丢数据(与 B 通道同规则) */
3189
+ var kAvailA = CONTENT_BOTTOM - mRegK.y;
3190
+ var kCap = Math.max(1, Math.floor(kAvailA / 0.42));
3175
3191
  var kRows = Math.min(kmets.length, kCap);
3176
- var kRowH = fitRowH(CONTENT_BOTTOM - mRegK.y, kRows, K.metricRowH, 0.42);
3192
+ if (kRows < kmets.length && typeof console !== 'undefined')
3193
+ console.warn('[pptx-export] KPI 页「' + (sec.title || '') + '」支撑指标 ' + kmets.length +
3194
+ ' 个超出容量,仅渲染前 ' + kRows + ' 个 —— 建议拆页');
3195
+ var kRowH = fitRowH(kAvailA, kRows, K.metricRowH, 0.42);
3177
3196
  var kTopH = Math.min(0.55, kRowH * 0.62);
3178
3197
  kmets.slice(0, kRows).forEach(function (m, i) {
3179
3198
  var ky = mRegK.y + i * kRowH;
@@ -3324,9 +3343,20 @@ function slidesOf(model, S) {
3324
3343
  var lt = isRec(l) ? (l.t || '') : String(l[0] || '');
3325
3344
  var ld = isRec(l) ? (l.d || '') : String(l[1] || '');
3326
3345
  sh.push(shape('roundRect', x2, y2, w2, rowHP, acc ? S.soft : S.surface, { adj: 5000, line: acc ? undefined : S.line }));
3327
- var lwP = Math.min(P.labelW, w2 - 0.44);
3328
- sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3329
- if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, w2 - 0.44 - lwP, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3346
+ var lwP = Math.min(P.labelW, (w2 - 0.44) * (P.labelFrac == null ? 0.32 : P.labelFrac));
3347
+ var descW = w2 - 0.44 - lwP;
3348
+ /* 窄层判定:说明列 < 1.2in,或标题在标题列内放不下单行 → 单框混排(与 B 通道同规则) */
3349
+ var narrowP = descW < 1.2 || (ld && estLines(lt, lwP, 13.5) > 1) || (!ld && estLines(lt, w2 - 0.44, 13.5) > 1);
3350
+ if (narrowP) {
3351
+ /* 顶层窄 → 标题上、说明下单框混排(HTML 窄屏 .pyr__lvl 即单列,与 B 通道同规则) */
3352
+ sh.push(txSp(x2 + 0.22, y2 + 0.03, w2 - 0.44, 0.30,
3353
+ [[{ t: lt, sz: 12.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]]));
3354
+ sh.push(txSp(x2 + 0.22, y2 + 0.33, w2 - 0.44, Math.max(0.2, rowHP - 0.36),
3355
+ [[{ t: ld, sz: 10.5, col: S.faint, font: S.font }]]));
3356
+ } else {
3357
+ sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3358
+ if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, descW, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3359
+ }
3330
3360
  });
3331
3361
  } else if (type === 'steps') {
3332
3362
  var S2 = PT.steps, st = sec.steps || [], maxPer = S2.maxPerRow || 6, groups = sec.groups || [];
@@ -3675,12 +3705,12 @@ function slidesOf(model, S) {
3675
3705
  var eReg = regOf('exhibit', 'primary')
3676
3706
  || { x: MX, y: PT.exhibit.chartY, w: CW, badgeY: PT.exhibit.badgeY };
3677
3707
  if (sec.exhibitNo) {
3678
- sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: String(sec.exhibitNo).toUpperCase(), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3708
+ sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: exhibitBadge(sec.exhibitNo), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3679
3709
  }
3680
3710
  var ec2 = sec.chart || {};
3681
3711
  if (ec2.labels && ec2.values) {
3682
3712
  var edcols2 = (ec2.colors || dataColors(model.style, model.theme));
3683
- var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!sec.footnote) - eReg.y - 0.05);
3713
+ var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note)) - eReg.y - 0.05);
3684
3714
  if (ec2.type === 'hbar') {
3685
3715
  chartBlockShapes(sh, ec2, S, eReg.x, eReg.y, eReg.w, hh2, edcols2);
3686
3716
  } else {
@@ -1430,6 +1430,8 @@ transition:color .18s,background-color .18s}
1430
1430
  </div>
1431
1431
  </section>
1432
1432
 
1433
+ <!-- __TOPPPT_CONTENT_END__ -->
1434
+
1433
1435
  <!-- ══ 页脚 ══ -->
1434
1436
  <footer class="foot">
1435
1437
  <div class="wrap foot__in">
@@ -1443,7 +1445,6 @@ transition:color .18s,background-color .18s}
1443
1445
  <div class="t-xs">密级说明</div>
1444
1446
  </div>
1445
1447
  </footer>
1446
- <!-- __TOPPPT_CONTENT_END__ -->
1447
1448
 
1448
1449
  <!-- ══ 页码指示(翻页导航) ══ -->
1449
1450
  <aside class="pager" id="pager" aria-label="页码导航">
@@ -2099,7 +2100,7 @@ window.REPORT_MODEL = {
2099
2100
 
2100
2101
  /* __TOPPPT_RUNTIME_START__ */
2101
2102
  /* ══ PPTX 导出运行时(assets/pptx-export.js 的内联副本 · 由 scripts/sync_runtime.py 注入,禁止手改) ══ */
2102
- /* __TOPPPT_RUNTIME_SHA__:af6e25f25fd2e116 */
2103
+ /* __TOPPPT_RUNTIME_SHA__:a4c909346759fe9c */
2103
2104
  /* ═══════════════════════════════════════════════════════════════════════════
2104
2105
  * TopPPT HTML· 浏览器端 PPTX 预览运行时
2105
2106
  * 零依赖、随报告单文件分发;OOXML 序列化器(仅供预览,页面不导出文件)。
@@ -2154,7 +2155,7 @@ function isRec(v) { return !!v && typeof v === 'object' && !Array.isArray(v); }
2154
2155
  var PW = 13.333, PH = 7.5, MX = 0.6, CW = PW - 2 * MX, EMU = 914400;
2155
2156
  var TS_BASE = {"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10};
2156
2157
  var MTS = {"presentation":{"coverTitle":44,"coverSub":18,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10},"research":{"coverTitle":36,"coverSub":14,"h1":22,"h2":13.5,"lead":11.5,"body":10.5,"caption":9,"micro":8.5},"architecture":{"coverTitle":44,"coverSub":19,"h1":30,"h2":17,"lead":14,"body":13,"caption":11,"micro":10}};
2157
- var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":5.3,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
2158
+ var PT = {"layout":{"contentTop":2.35,"contentBottom":6.9,"contentBottomWithNote":6.4,"pageNumY":7.0},"common":{"headEyebrowY":0.48,"headTitleY":0.82,"headRuleY":1.72,"leadY":1.88,"bodyY":2.35,"bodyYWithLead":2.55,"pagerY":7.0},"cover":{"metaY":0.7,"titleY":2.4,"titleH":2.0,"subtitleY":4.5,"subtitleH":0.8},"closing":{"eyebrowY":0.7,"titleY":1.2,"titleH":1.2,"pointsY":3.0,"pointTitleH":0.6,"pointBodyH":1.2},"points":{"listY":2.5,"rowH":0.72,"rowHMin":0.5,"markSize":0.14,"metricY":4.7,"metricW":2.6,"metricValH":0.9,"metricCapY":5.6},"metrics":{"bandY":3.1,"cardH":2.3,"valY":3.45,"valH":1.1,"capY":4.55,"capH":0.7,"gap":0.3,"maxW":2.9},"table":{"y":2.5,"rowH":0.55,"rowHMin":0.32,"headRowH":0.5},"bar":{"hbarY0":2.6,"hbarY1":6.25,"chartX":0.6,"chartY":2.95,"chartW":1.2,"chartH":3.35,"noteY":6.55},"note":{"y":6.55,"h":0.4},"exhibit":{"badgeY":2.35,"chartY":2.75,"chartH":3.25,"soWhatY":6.05,"footnoteY":6.72},"twocol":{"colGap":0.5,"bodyH":3.6,"rowHMin":0.5},"hbar":{"labelW":1.9,"valW":1.0,"rowH":0.55,"barRatio":0.5},"diagram":{"layerBarW":1.35,"layerGap":0.15,"nodeGap":0.15,"bodyStartY":2.9,"maxLayerH":1.15,"nodeMaxW":2.2},"split":{"leftW":0.55,"rightW":0.415,"rightX":0.585,"pointsY":2.7,"rowH":0.78,"capY":2.55,"chartY":3.0,"chartH":3.7,"tableY":2.7,"tableRowH":0.5},"cards":{"startY":3.0,"gap":0.25,"maxH":2.0,"titleH":0.4},"timeline":{"labelY":2.95,"axisY":3.58,"dotY":3.51,"dotR":0.18,"nameY":3.9,"descY":4.45,"descH":1.2},"research":{"col3Gap":0.38,"matrixLabelW":1.5,"matrixCellH":0.85,"matrixY":2.2,"denseTableY":2.2,"denseRowH":0.42,"halfTableW":0.52,"halfChartX":0.57,"halfChartW":0.43},"arch":{"fullStartY":2.1,"fullEndY":6.9,"laneH":0.72,"laneHMin":0.5,"laneGap":0.14,"laneHeadW":1.3,"stepGap":0.12,"stepMaxW":1.9},"kpi":{"heroY":2.9,"heroW":0.52,"heroH":1.6,"dividerX":0.56,"metricY0":2.95,"metricRowH":0.85},"comparison":{"panelGap":0.4,"panelY":2.55,"panelH":3.4,"titleH":0.45,"rowH":0.62},"quote":{"markY":1.75,"textY":2.7,"textH":2.3,"authorY":5.25,"contextY":5.8},"donut":{"centerX":3.05,"centerY":4.6,"r":1.6,"holeR":0.95,"legendX":5.6,"legendRowH":0.55,"legendLabelW":3.4,"legendValW":1.3,"legendPctX":10.8,"legendPctW":1.3},"steps":{"y":3.05,"barH":1.35,"gap":0.12,"arrowW":0.3,"numH":0.3,"titleH":0.34,"pad":0.08,"maxPerRow":6},"heatmap":{"y":2.6,"labelW":1.7,"headH":0.42,"cellH":0.6,"cellGap":0.06,"legendW":1.6},"pyramid":{"y":2.35,"rowH":0.72,"gap":0.08,"minW":0.34,"labelW":3.2},"bullet":{"y":2.6,"rowH":0.8,"labelW":2.4,"valW":1.7,"barH":0.26},"image":{"y":2.3,"h":4.2,"halfW":0.56,"halfGap":0.06,"capY":6.6,"capH":0.3,"radius":0.09,"noteRowH":0.62,"gridGap":0.16,"gridCols":{"2":2,"3":3,"4":4,"6":3},"gridCapH":0.28,"compareGap":0.3,"compareTagH":0.26,"wallCellH":0.92,"wallGap":0.18,"wallMaxRows":2},"flagbar":{"hdH":0.26,"rowH":0.24,"maxRows":3,"gap":0.12},"sankey":{"y":2.45,"h":4.1,"nodeW":0.32,"nodeGap":0.14,"labelW":1.55,"minBandH":0.22,"maxNodes":12,"maxFlows":24},"treemap":{"y":2.45,"h":4.1,"gap":0.05,"labelMinH":0.34,"maxLeaves":16,"maxDepth":3},"boxplot":{"y":2.7,"h":3.7,"labelW":1.5,"groupGap":0.3,"boxMaxW":0.9,"whiskerCapW":0.34,"maxGroups":8},"network":{"y":2.4,"h":4.2,"nodeR":0.28,"nodeRMin":0.18,"labelMaxW":1.4,"maxNodes":18,"maxEdges":30},"marimekko":{"y":2.6,"h":3.75,"labelW":1.55,"colGap":0.06,"legendH":0.42,"maxCols":6,"maxSegs":4},"streamgraph":{"y":2.6,"h":3.75,"labelW":1.4,"bandMinH":0.12,"maxSeries":6}};
2158
2159
  var PRESETS = {
2159
2160
  'business-blue': { accent:'1A73E8', ink:'202124', body:'5F6368', faint:'80868B', bg:'FFFFFF', surface:'F8F9FA', line:'DADCE0', soft:'E8F0FE', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
2160
2161
  'apple-mono': { accent:'1D1D1F', ink:'1D1D1F', body:'6E6E73', faint:'86868B', bg:'FFFFFF', surface:'F5F5F7', line:'D2D2D7', soft:'F5F5F7', onAccent:'FFFFFF', font:'Microsoft YaHei', fontDisplay:'Microsoft YaHei' },
@@ -3095,7 +3096,9 @@ function infoTableRows(sec) {
3095
3096
  if (t === 'marimekko') {
3096
3097
  var head = ['列', '总量' + u].concat((sec.legend || []).map(String));
3097
3098
  return [head].concat((sec.cols || []).map(function (c, i) {
3098
- return [String(c[0]), String(c[1])].concat(((sec.cells || [])[i] || []).map(String));
3099
+ return [String(c[0]), String(c[1])].concat((((sec.cells || [])[i] || []).map(function (el) {
3100
+ return Array.isArray(el) ? String(el[0]) + ' ' + el[1] : String(el);
3101
+ })));
3099
3102
  }));
3100
3103
  }
3101
3104
  if (t === 'streamgraph') {
@@ -3243,7 +3246,11 @@ function infoApprox(sh, sec, S, y0, y1) {
3243
3246
  var cx1 = MX;
3244
3247
  cols.forEach(function (c, i) {
3245
3248
  var cw = Math.max(0.2, (Number(c[1]) || 0) / total * availW);
3246
- var shares = ((sec.cells || [])[i] || []).map(Number);
3249
+ /* 单元格兼容 [标签,数值] 对(与 B 通道 marimekkoSegs 同规则);非数值 → 0 */
3250
+ var shares = ((sec.cells || [])[i] || []).map(function (el) {
3251
+ var v = Number(Array.isArray(el) ? el[1] : el);
3252
+ return isFinite(v) ? v : 0;
3253
+ });
3247
3254
  var sum = shares.reduce(function (a, b) { return a + b; }, 0) || 1;
3248
3255
  var cy = P.y0;
3249
3256
  shares.forEach(function (v, k) {
@@ -3393,13 +3400,20 @@ function slidesOf(model, S) {
3393
3400
  });
3394
3401
  }
3395
3402
 
3396
- /* 章节页 */
3403
+ /* Exhibit 徽标文本:纯编号补 "Exhibit " 前缀(HTML 为 `Exhibit {no}` + CSS uppercase);
3404
+ 调用方已带前缀的不重复(与 B 通道 exhibitBadge 同规则) */
3405
+ function exhibitBadge(no) {
3406
+ var t = String(no == null ? '' : no).trim();
3407
+ if (!t) return t;
3408
+ return /^exhibit[\s\-:]*/i.test(t) ? t.toUpperCase() : ('EXHIBIT ' + t.toUpperCase());
3409
+ }
3410
+ /* 章节页 */
3397
3411
  (model.sections || []).forEach(function (sec) {
3398
3412
  var type = sec.type || 'points';
3399
3413
  var sh = [];
3400
3414
  if (type !== 'quote') head(sh, sec.eyebrow, sec.title, sec.lead);
3401
3415
  /* 非 exhibit 页型也可带 Exhibit 编号(帧头徽标;正文区下移让位,与 B 通道同规则) */
3402
- var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? String(sec.exhibitNo).toUpperCase() : null;
3416
+ var exBadge = (type !== 'exhibit' && sec.exhibitNo) ? exhibitBadge(sec.exhibitNo) : null;
3403
3417
  var bodyY0 = sec.lead ? PT.common.bodyYWithLead : CONTENT_TOP;
3404
3418
  var bodyY = exBadge ? bodyY0 + 0.42 : bodyY0;
3405
3419
  if (exBadge) {
@@ -3410,7 +3424,7 @@ function slidesOf(model, S) {
3410
3424
  var _F = PT.flagbar || { hdH: 0.26, rowH: 0.24, maxRows: 3, gap: 0.12 };
3411
3425
  var flagH = flagItems.length
3412
3426
  ? (_F.hdH + Math.min(_F.maxRows, flagItems.length) * _F.rowH + 0.06) : 0;
3413
- var bodyBottom = chartBottom(!!sec.soWhat, !!sec.footnote);
3427
+ var bodyBottom = chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note));
3414
3428
  var flagY = 0;
3415
3429
  if (flagH) {
3416
3430
  flagY = CONTENT_BOTTOM - flagH;
@@ -3444,9 +3458,14 @@ function slidesOf(model, S) {
3444
3458
  sh.push(shape('rect', kdivX, K.heroY + 0.15, 0.025, 3.1, S.line));
3445
3459
  var mRegK = regOf('kpi', 'metrics') || { x: kdivX + 0.35, y: K.metricY0, w: CW * (1 - K.dividerX) - 0.5 };
3446
3460
  var kmets = sec.metrics || [];
3447
- var kCap = Math.max(1, Math.floor((CONTENT_BOTTOM - mRegK.y) / K.metricRowH));
3461
+ /* 容量按最小允许行高判断,行高按全部指标自适应压缩 —— 禁静默丢数据(与 B 通道同规则) */
3462
+ var kAvailA = CONTENT_BOTTOM - mRegK.y;
3463
+ var kCap = Math.max(1, Math.floor(kAvailA / 0.42));
3448
3464
  var kRows = Math.min(kmets.length, kCap);
3449
- var kRowH = fitRowH(CONTENT_BOTTOM - mRegK.y, kRows, K.metricRowH, 0.42);
3465
+ if (kRows < kmets.length && typeof console !== 'undefined')
3466
+ console.warn('[pptx-export] KPI 页「' + (sec.title || '') + '」支撑指标 ' + kmets.length +
3467
+ ' 个超出容量,仅渲染前 ' + kRows + ' 个 —— 建议拆页');
3468
+ var kRowH = fitRowH(kAvailA, kRows, K.metricRowH, 0.42);
3450
3469
  var kTopH = Math.min(0.55, kRowH * 0.62);
3451
3470
  kmets.slice(0, kRows).forEach(function (m, i) {
3452
3471
  var ky = mRegK.y + i * kRowH;
@@ -3597,9 +3616,20 @@ function slidesOf(model, S) {
3597
3616
  var lt = isRec(l) ? (l.t || '') : String(l[0] || '');
3598
3617
  var ld = isRec(l) ? (l.d || '') : String(l[1] || '');
3599
3618
  sh.push(shape('roundRect', x2, y2, w2, rowHP, acc ? S.soft : S.surface, { adj: 5000, line: acc ? undefined : S.line }));
3600
- var lwP = Math.min(P.labelW, w2 - 0.44);
3601
- sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3602
- if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, w2 - 0.44 - lwP, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3619
+ var lwP = Math.min(P.labelW, (w2 - 0.44) * (P.labelFrac == null ? 0.32 : P.labelFrac));
3620
+ var descW = w2 - 0.44 - lwP;
3621
+ /* 窄层判定:说明列 < 1.2in,或标题在标题列内放不下单行 → 单框混排(与 B 通道同规则) */
3622
+ var narrowP = descW < 1.2 || (ld && estLines(lt, lwP, 13.5) > 1) || (!ld && estLines(lt, w2 - 0.44, 13.5) > 1);
3623
+ if (narrowP) {
3624
+ /* 顶层窄 → 标题上、说明下单框混排(HTML 窄屏 .pyr__lvl 即单列,与 B 通道同规则) */
3625
+ sh.push(txSp(x2 + 0.22, y2 + 0.03, w2 - 0.44, 0.30,
3626
+ [[{ t: lt, sz: 12.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]]));
3627
+ sh.push(txSp(x2 + 0.22, y2 + 0.33, w2 - 0.44, Math.max(0.2, rowHP - 0.36),
3628
+ [[{ t: ld, sz: 10.5, col: S.faint, font: S.font }]]));
3629
+ } else {
3630
+ sh.push(txSp(x2 + 0.22, y2, lwP, rowHP, [[{ t: lt, sz: 13.5, b: 1, col: acc ? S.accent : S.ink, font: S.font }]], { anchor: 'ctr' }));
3631
+ if (ld) sh.push(txSp(x2 + 0.22 + lwP, y2, descW, rowHP, [[{ t: ld, sz: 11, col: S.faint, font: S.font }]], { anchor: 'ctr' }));
3632
+ }
3603
3633
  });
3604
3634
  } else if (type === 'steps') {
3605
3635
  var S2 = PT.steps, st = sec.steps || [], maxPer = S2.maxPerRow || 6, groups = sec.groups || [];
@@ -3948,12 +3978,12 @@ function slidesOf(model, S) {
3948
3978
  var eReg = regOf('exhibit', 'primary')
3949
3979
  || { x: MX, y: PT.exhibit.chartY, w: CW, badgeY: PT.exhibit.badgeY };
3950
3980
  if (sec.exhibitNo) {
3951
- sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: String(sec.exhibitNo).toUpperCase(), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3981
+ sh.push(txSp(MX, eReg.badgeY != null ? eReg.badgeY : PT.exhibit.badgeY, CW, 0.35, [[{ t: exhibitBadge(sec.exhibitNo), sz: 11.5, b: 1, col: S.accent, font: S.font, spc: 200 }]]));
3952
3982
  }
3953
3983
  var ec2 = sec.chart || {};
3954
3984
  if (ec2.labels && ec2.values) {
3955
3985
  var edcols2 = (ec2.colors || dataColors(model.style, model.theme));
3956
- var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!sec.footnote) - eReg.y - 0.05);
3986
+ var hh2 = Math.max(1.2, chartBottom(!!sec.soWhat, !!(sec.footnote || sec.note)) - eReg.y - 0.05);
3957
3987
  if (ec2.type === 'hbar') {
3958
3988
  chartBlockShapes(sh, ec2, S, eReg.x, eReg.y, eReg.w, hh2, edcols2);
3959
3989
  } else {
@@ -71,7 +71,7 @@ def strip_blocks(css: str) -> str:
71
71
 
72
72
  def main() -> int:
73
73
  if not ENGINE.exists():
74
- print('错误: 缺 assets/templates/engine.css')
74
+ print('错误: 缺 assets/templates/engine.css')
75
75
  return 2
76
76
 
77
77
  selector_zone = strip_blocks(ENGINE.read_text(encoding='utf-8'))