@taloswork/ose-shared 0.1.7 → 0.1.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 (166) hide show
  1. package/package.json +3 -3
  2. package/skills/cozy-static-svg/SKILL.md +76 -0
  3. package/skills/cozy-static-svg/references/approved-preview.png +0 -0
  4. package/skills/cozy-static-svg/references/cross-platform.md +73 -0
  5. package/skills/cozy-static-svg/references/moon_keeps_watch.svg +229 -0
  6. package/skills/cozy-static-svg/references/style-anchor.md +271 -0
  7. package/skills/cozy-static-svg/scripts/artkit.py +321 -0
  8. package/skills/cozy-static-svg/scripts/to_png.py +333 -0
  9. package/skills/diagram-design/SKILL.md +568 -0
  10. package/skills/diagram-design/assets/example-architecture-dark.html +182 -0
  11. package/skills/diagram-design/assets/example-architecture-full.html +194 -0
  12. package/skills/diagram-design/assets/example-architecture.html +183 -0
  13. package/skills/diagram-design/assets/example-bar-dark.html +129 -0
  14. package/skills/diagram-design/assets/example-bar-full.html +105 -0
  15. package/skills/diagram-design/assets/example-bar.html +129 -0
  16. package/skills/diagram-design/assets/example-data-flow-dark.html +143 -0
  17. package/skills/diagram-design/assets/example-data-flow-full.html +185 -0
  18. package/skills/diagram-design/assets/example-data-flow.html +143 -0
  19. package/skills/diagram-design/assets/example-datalake-dark.html +243 -0
  20. package/skills/diagram-design/assets/example-datalake-full.html +248 -0
  21. package/skills/diagram-design/assets/example-datalake.html +269 -0
  22. package/skills/diagram-design/assets/example-dp-integration-dark.html +80 -0
  23. package/skills/diagram-design/assets/example-dp-integration-full.html +90 -0
  24. package/skills/diagram-design/assets/example-dp-integration.html +80 -0
  25. package/skills/diagram-design/assets/example-dp-security-matrix-dark.html +31 -0
  26. package/skills/diagram-design/assets/example-dp-security-matrix-full.html +32 -0
  27. package/skills/diagram-design/assets/example-dp-security-matrix.html +88 -0
  28. package/skills/diagram-design/assets/example-er-dark.html +202 -0
  29. package/skills/diagram-design/assets/example-er-full.html +205 -0
  30. package/skills/diagram-design/assets/example-er.html +202 -0
  31. package/skills/diagram-design/assets/example-flowchart-dark.html +156 -0
  32. package/skills/diagram-design/assets/example-flowchart-full.html +159 -0
  33. package/skills/diagram-design/assets/example-flowchart.html +156 -0
  34. package/skills/diagram-design/assets/example-gantt-dark.html +137 -0
  35. package/skills/diagram-design/assets/example-gantt-full.html +127 -0
  36. package/skills/diagram-design/assets/example-gantt.html +137 -0
  37. package/skills/diagram-design/assets/example-high-level-dark.html +251 -0
  38. package/skills/diagram-design/assets/example-high-level-full.html +247 -0
  39. package/skills/diagram-design/assets/example-high-level-vertical-dark.html +274 -0
  40. package/skills/diagram-design/assets/example-high-level-vertical-full.html +252 -0
  41. package/skills/diagram-design/assets/example-high-level-vertical.html +325 -0
  42. package/skills/diagram-design/assets/example-high-level.html +301 -0
  43. package/skills/diagram-design/assets/example-import-drawio.html +185 -0
  44. package/skills/diagram-design/assets/example-import-mermaid.html +70 -0
  45. package/skills/diagram-design/assets/example-it-state-dark.html +90 -0
  46. package/skills/diagram-design/assets/example-it-state-full.html +69 -0
  47. package/skills/diagram-design/assets/example-it-state.html +128 -0
  48. package/skills/diagram-design/assets/example-layers-dark.html +123 -0
  49. package/skills/diagram-design/assets/example-layers-full.html +126 -0
  50. package/skills/diagram-design/assets/example-layers.html +123 -0
  51. package/skills/diagram-design/assets/example-line-dark.html +111 -0
  52. package/skills/diagram-design/assets/example-line-full.html +105 -0
  53. package/skills/diagram-design/assets/example-line.html +111 -0
  54. package/skills/diagram-design/assets/example-loop-dark.html +100 -0
  55. package/skills/diagram-design/assets/example-loop-full.html +137 -0
  56. package/skills/diagram-design/assets/example-loop-terminal.html +347 -0
  57. package/skills/diagram-design/assets/example-loop.html +100 -0
  58. package/skills/diagram-design/assets/example-medallion-dark.html +159 -0
  59. package/skills/diagram-design/assets/example-medallion-full.html +201 -0
  60. package/skills/diagram-design/assets/example-medallion.html +159 -0
  61. package/skills/diagram-design/assets/example-nested-dark.html +132 -0
  62. package/skills/diagram-design/assets/example-nested-full.html +135 -0
  63. package/skills/diagram-design/assets/example-nested.html +136 -0
  64. package/skills/diagram-design/assets/example-org-chart-dark.html +45 -0
  65. package/skills/diagram-design/assets/example-org-chart-full.html +45 -0
  66. package/skills/diagram-design/assets/example-org-chart.html +45 -0
  67. package/skills/diagram-design/assets/example-paved-road-animated.html +546 -0
  68. package/skills/diagram-design/assets/example-policy-trace-animated.html +490 -0
  69. package/skills/diagram-design/assets/example-process-dark.html +64 -0
  70. package/skills/diagram-design/assets/example-process-full.html +74 -0
  71. package/skills/diagram-design/assets/example-process.html +64 -0
  72. package/skills/diagram-design/assets/example-pyramid-dark.html +119 -0
  73. package/skills/diagram-design/assets/example-pyramid-full.html +122 -0
  74. package/skills/diagram-design/assets/example-pyramid.html +119 -0
  75. package/skills/diagram-design/assets/example-quadrant-consultant.html +166 -0
  76. package/skills/diagram-design/assets/example-quadrant-dark.html +135 -0
  77. package/skills/diagram-design/assets/example-quadrant-full.html +138 -0
  78. package/skills/diagram-design/assets/example-quadrant.html +135 -0
  79. package/skills/diagram-design/assets/example-queue-animated.html +577 -0
  80. package/skills/diagram-design/assets/example-radar-dark.html +139 -0
  81. package/skills/diagram-design/assets/example-radar-full.html +135 -0
  82. package/skills/diagram-design/assets/example-radar.html +139 -0
  83. package/skills/diagram-design/assets/example-scatter-dark.html +141 -0
  84. package/skills/diagram-design/assets/example-scatter-full.html +116 -0
  85. package/skills/diagram-design/assets/example-scatter.html +141 -0
  86. package/skills/diagram-design/assets/example-sequence-dark.html +222 -0
  87. package/skills/diagram-design/assets/example-sequence-full.html +388 -0
  88. package/skills/diagram-design/assets/example-sequence-oauth-dark.html +188 -0
  89. package/skills/diagram-design/assets/example-sequence-oauth-full.html +350 -0
  90. package/skills/diagram-design/assets/example-sequence-oauth.html +227 -0
  91. package/skills/diagram-design/assets/example-sequence.html +222 -0
  92. package/skills/diagram-design/assets/example-state-dark.html +147 -0
  93. package/skills/diagram-design/assets/example-state-full.html +150 -0
  94. package/skills/diagram-design/assets/example-state.html +147 -0
  95. package/skills/diagram-design/assets/example-swimlane-dark.html +172 -0
  96. package/skills/diagram-design/assets/example-swimlane-full.html +175 -0
  97. package/skills/diagram-design/assets/example-swimlane.html +172 -0
  98. package/skills/diagram-design/assets/example-timeline-dark.html +135 -0
  99. package/skills/diagram-design/assets/example-timeline-full.html +138 -0
  100. package/skills/diagram-design/assets/example-timeline.html +135 -0
  101. package/skills/diagram-design/assets/example-tree-dark.html +173 -0
  102. package/skills/diagram-design/assets/example-tree-full.html +176 -0
  103. package/skills/diagram-design/assets/example-tree.html +173 -0
  104. package/skills/diagram-design/assets/example-venn-dark.html +132 -0
  105. package/skills/diagram-design/assets/example-venn-full.html +135 -0
  106. package/skills/diagram-design/assets/example-venn.html +110 -0
  107. package/skills/diagram-design/assets/icons.html +230 -0
  108. package/skills/diagram-design/assets/index.html +369 -0
  109. package/skills/diagram-design/assets/template-dark.html +85 -0
  110. package/skills/diagram-design/assets/template-full.html +413 -0
  111. package/skills/diagram-design/assets/template-motion.html +434 -0
  112. package/skills/diagram-design/assets/template-terminal.html +173 -0
  113. package/skills/diagram-design/assets/template.html +86 -0
  114. package/skills/diagram-design/references/animation.md +141 -0
  115. package/skills/diagram-design/references/export.md +136 -0
  116. package/skills/diagram-design/references/import-drawio.md +171 -0
  117. package/skills/diagram-design/references/import-mermaid.md +126 -0
  118. package/skills/diagram-design/references/onboarding.md +297 -0
  119. package/skills/diagram-design/references/output-spec.md +181 -0
  120. package/skills/diagram-design/references/primitive-annotation.md +36 -0
  121. package/skills/diagram-design/references/primitive-icons.md +827 -0
  122. package/skills/diagram-design/references/primitive-sketchy.md +43 -0
  123. package/skills/diagram-design/references/primitive-terminal.md +76 -0
  124. package/skills/diagram-design/references/semantic-patterns.md +122 -0
  125. package/skills/diagram-design/references/style-guide.md +139 -0
  126. package/skills/diagram-design/references/type-architecture.md +78 -0
  127. package/skills/diagram-design/references/type-bar.md +48 -0
  128. package/skills/diagram-design/references/type-data-flow.md +374 -0
  129. package/skills/diagram-design/references/type-dp-integration.md +410 -0
  130. package/skills/diagram-design/references/type-dp-security-matrix.md +379 -0
  131. package/skills/diagram-design/references/type-er.md +23 -0
  132. package/skills/diagram-design/references/type-flowchart.md +23 -0
  133. package/skills/diagram-design/references/type-gantt.md +45 -0
  134. package/skills/diagram-design/references/type-high-level.md +458 -0
  135. package/skills/diagram-design/references/type-it-state.md +470 -0
  136. package/skills/diagram-design/references/type-layers.md +26 -0
  137. package/skills/diagram-design/references/type-line.md +44 -0
  138. package/skills/diagram-design/references/type-loop.md +223 -0
  139. package/skills/diagram-design/references/type-medallion.md +356 -0
  140. package/skills/diagram-design/references/type-nested.md +22 -0
  141. package/skills/diagram-design/references/type-org-chart.md +44 -0
  142. package/skills/diagram-design/references/type-process.md +495 -0
  143. package/skills/diagram-design/references/type-pyramid.md +33 -0
  144. package/skills/diagram-design/references/type-quadrant.md +81 -0
  145. package/skills/diagram-design/references/type-radar.md +80 -0
  146. package/skills/diagram-design/references/type-scatter.md +39 -0
  147. package/skills/diagram-design/references/type-sequence.md +130 -0
  148. package/skills/diagram-design/references/type-state.md +21 -0
  149. package/skills/diagram-design/references/type-swimlane.md +20 -0
  150. package/skills/diagram-design/references/type-timeline.md +20 -0
  151. package/skills/diagram-design/references/type-tree.md +24 -0
  152. package/skills/diagram-design/references/type-venn.md +26 -0
  153. package/skills/diagram-design/scripts/drawio_extract.py +856 -0
  154. package/skills/diagram-design/scripts/mermaid_extract.py +1285 -0
  155. package/skills/diagram-design/scripts/self_check.py +389 -0
  156. package/skills/document/bin/doc-gen.cjs +3 -6
  157. package/skills/document/bin/html2pptx.cjs +17 -9
  158. package/skills/document/bin/pptx-clone.cjs +41 -30
  159. package/skills/document/bin/pptx-embed-fonts.cjs +6 -2
  160. package/skills/document/bin/pptx-slide.cjs +46 -50
  161. package/skills/document/content-pipeline.md +54 -5
  162. package/skills/document/layouts/README.md +8 -0
  163. package/skills/document/layouts/blocks-2x2.tpl +19 -9
  164. package/skills/document/layouts/cards-3.tpl +1 -1
  165. package/skills/document/layouts/org-tree.tpl +1 -1
  166. package/skills/document/layouts/steps-vertical.tpl +1 -1
@@ -9820,11 +9820,40 @@ var import_promises = require("node:fs/promises");
9820
9820
 
9821
9821
  // packages/core/dist/document/pptx-slide.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
+
9824
+ // packages/core/dist/document/pptx-register-slide.js
9823
9825
  var SLIDE_CT = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
9824
9826
  var SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
9827
+ async function text(zip, path) {
9828
+ const f = zip.file(path);
9829
+ if (!f)
9830
+ throw new Error(`not a PowerPoint file (${path} missing)`);
9831
+ return f.async("string");
9832
+ }
9833
+ async function registerSlidePart(zip, newNum, newXmlPath) {
9834
+ const ctPath = "[Content_Types].xml";
9835
+ const ct = await text(zip, ctPath);
9836
+ if (!ct.includes(`PartName="/${newXmlPath}"`)) {
9837
+ zip.file(ctPath, ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT}"/></Types>`));
9838
+ }
9839
+ const presRelsPath = "ppt/_rels/presentation.xml.rels";
9840
+ const presRels = await text(zip, presRelsPath);
9841
+ const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
9842
+ const newRid = `rId${maxRid + 1}`;
9843
+ zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE}" Target="slides/slide${newNum}.xml"/></Relationships>`));
9844
+ const presPath = "ppt/presentation.xml";
9845
+ const pres = await text(zip, presPath);
9846
+ const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
9847
+ const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
9848
+ if (updated === pres)
9849
+ throw new Error("could not locate the slide list in presentation.xml");
9850
+ zip.file(presPath, updated);
9851
+ }
9852
+
9853
+ // packages/core/dist/document/pptx-slide.js
9825
9854
  var LAYOUT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
9826
9855
  var BLANK_SLIDE_XML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/></p:spTree></p:cSld><p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr></p:sld>';
9827
- async function text(zip, path) {
9856
+ async function text2(zip, path) {
9828
9857
  const f = zip.file(path);
9829
9858
  if (!f)
9830
9859
  throw new Error(`not a PowerPoint file (${path} missing)`);
@@ -9872,29 +9901,14 @@ async function addBlankSlide(bytes, opts = {}) {
9872
9901
  zip.file(newXmlPath, BLANK_SLIDE_XML);
9873
9902
  zip.file(`ppt/slides/_rels/slide${newNum}.xml.rels`, `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
9874
9903
  <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="${LAYOUT_REL_TYPE}" Target="../slideLayouts/slideLayout${layout}.xml"/></Relationships>`);
9875
- const ct = await text(zip, "[Content_Types].xml");
9876
- if (!ct.includes(`PartName="/${newXmlPath}"`)) {
9877
- zip.file("[Content_Types].xml", ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT}"/></Types>`));
9878
- }
9879
- const presRelsPath = "ppt/_rels/presentation.xml.rels";
9880
- const presRels = await text(zip, presRelsPath);
9881
- const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
9882
- const newRid = `rId${maxRid + 1}`;
9883
- zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE}" Target="slides/slide${newNum}.xml"/></Relationships>`));
9884
- const presPath = "ppt/presentation.xml";
9885
- const pres = await text(zip, presPath);
9886
- const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
9887
- const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
9888
- if (updated === pres)
9889
- throw new Error("could not locate the slide list in presentation.xml");
9890
- zip.file(presPath, updated);
9904
+ await registerSlidePart(zip, newNum, newXmlPath);
9891
9905
  const out2 = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
9892
9906
  return { bytes: new Uint8Array(out2), newSlideNumber: newNum, layout };
9893
9907
  }
9894
9908
  async function reorderPptxSlides(bytes, order) {
9895
9909
  const zip = await load(bytes);
9896
9910
  const presPath = "ppt/presentation.xml";
9897
- const pres = await text(zip, presPath);
9911
+ const pres = await text2(zip, presPath);
9898
9912
  const listMatch = /(<p:sldIdLst\b[^>]*>)([\s\S]*?)(<\/p:sldIdLst>)/.exec(pres);
9899
9913
  if (!listMatch)
9900
9914
  throw new Error("no <p:sldIdLst> in presentation.xml (corrupt deck?)");
@@ -9965,9 +9979,9 @@ function unescXml(s) {
9965
9979
  }
9966
9980
  });
9967
9981
  }
9968
- function visualWidth(text3) {
9982
+ function visualWidth(text4) {
9969
9983
  let w = 0;
9970
- for (const ch of text3) {
9984
+ for (const ch of text4) {
9971
9985
  const cp = ch.codePointAt(0);
9972
9986
  if (ch === " " || ch === " ")
9973
9987
  w += 0.35;
@@ -9996,9 +10010,9 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
9996
10010
  const segs = [];
9997
10011
  let flat = "";
9998
10012
  for (const m of para.matchAll(textRe)) {
9999
- const text3 = unescXml(m[2]);
10000
- segs.push({ el: m[0], attrs: m[1] ?? "", text: text3, start: flat.length });
10001
- flat += text3;
10013
+ const text4 = unescXml(m[2]);
10014
+ segs.push({ el: m[0], attrs: m[1] ?? "", text: text4, start: flat.length });
10015
+ flat += text4;
10002
10016
  }
10003
10017
  if (!flat.includes(find))
10004
10018
  return para;
@@ -10042,8 +10056,6 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
10042
10056
  }
10043
10057
 
10044
10058
  // packages/core/dist/document/pptx-clone.js
10045
- var SLIDE_CT2 = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
10046
- var SLIDE_REL_TYPE2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
10047
10059
  var EMU_PER_PT = 12700;
10048
10060
  function capacityWarning(slideXml, token, value) {
10049
10061
  const idx = slideXml.indexOf(token);
@@ -10076,7 +10088,7 @@ function capacityWarning(slideXml, token, value) {
10076
10088
  return void 0;
10077
10089
  return `${token}: replacement is ~${Math.ceil(width)} width-units, slot fits ~${Math.floor(capacity)} (${Math.round(widthPt)}\xD7${Math.round(heightPt)}pt box @ ${fontPt}pt) \u2014 likely overflow. Shorten the wording; do NOT shrink the font to make it fit.`;
10078
10090
  }
10079
- async function text2(zip, path) {
10091
+ async function text3(zip, path) {
10080
10092
  const f = zip.file(path);
10081
10093
  if (!f)
10082
10094
  throw new Error(`not a PowerPoint file (${path} missing)`);
@@ -10101,7 +10113,7 @@ async function clonePptxSlide(bytes, slideNumber, replacements = {}) {
10101
10113
  const newNum = Math.max(...slideNums) + 1;
10102
10114
  const srcXmlPath = `ppt/slides/slide${slideNumber}.xml`;
10103
10115
  const newXmlPath = `ppt/slides/slide${newNum}.xml`;
10104
- let slideXml = await text2(zip, srcXmlPath);
10116
+ let slideXml = await text3(zip, srcXmlPath);
10105
10117
  const replaced = [];
10106
10118
  const missing = [];
10107
10119
  const warnings = [];
@@ -10129,23 +10141,7 @@ async function clonePptxSlide(bytes, slideNumber, replacements = {}) {
10129
10141
  const rels = removeElement(await srcRels.async("string"), "Relationship", (el) => /Type="[^"]*\/notesSlide"/.test(el)).xml;
10130
10142
  zip.file(`ppt/slides/_rels/slide${newNum}.xml.rels`, rels);
10131
10143
  }
10132
- const ctPath = "[Content_Types].xml";
10133
- const ct = await text2(zip, ctPath);
10134
- if (!ct.includes(`PartName="/${newXmlPath}"`)) {
10135
- zip.file(ctPath, ct.replace("</Types>", `<Override PartName="/${newXmlPath}" ContentType="${SLIDE_CT2}"/></Types>`));
10136
- }
10137
- const presRelsPath = "ppt/_rels/presentation.xml.rels";
10138
- const presRels = await text2(zip, presRelsPath);
10139
- const maxRid = Math.max(0, ...[...presRels.matchAll(/Id="rId(\d+)"/g)].map((m) => Number(m[1])));
10140
- const newRid = `rId${maxRid + 1}`;
10141
- zip.file(presRelsPath, presRels.replace("</Relationships>", `<Relationship Id="${newRid}" Type="${SLIDE_REL_TYPE2}" Target="slides/slide${newNum}.xml"/></Relationships>`));
10142
- const presPath = "ppt/presentation.xml";
10143
- const pres = await text2(zip, presPath);
10144
- const maxSldId = Math.max(255, ...[...pres.matchAll(/<p:sldId id="(\d+)"/g)].map((m) => Number(m[1])));
10145
- const updated = pres.replace("</p:sldIdLst>", `<p:sldId id="${maxSldId + 1}" r:id="${newRid}"/></p:sldIdLst>`);
10146
- if (updated === pres)
10147
- throw new Error("could not locate the slide list in presentation.xml");
10148
- zip.file(presPath, updated);
10144
+ await registerSlidePart(zip, newNum, newXmlPath);
10149
10145
  const out2 = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
10150
10146
  return { bytes: new Uint8Array(out2), newSlideNumber: newNum, replaced, missing, warnings };
10151
10147
  }
@@ -10170,9 +10166,9 @@ async function removePptxSlide(bytes, slideNumber) {
10170
10166
  const xmlPath = `ppt/slides/slide${slideNumber}.xml`;
10171
10167
  const relsPath = `ppt/slides/_rels/slide${slideNumber}.xml.rels`;
10172
10168
  const presRelsPath = "ppt/_rels/presentation.xml.rels";
10173
- const presRels = await text2(zip, presRelsPath);
10169
+ const presRels = await text3(zip, presRelsPath);
10174
10170
  const targetRe = new RegExp(`Target="(/ppt/)?slides/slide${slideNumber}\\.xml"`);
10175
- const relMatch = findElement(presRels, "Relationship", (r) => r.includes(SLIDE_REL_TYPE2) && targetRe.test(r));
10171
+ const relMatch = findElement(presRels, "Relationship", (r) => r.includes(SLIDE_REL_TYPE) && targetRe.test(r));
10176
10172
  if (!relMatch)
10177
10173
  throw new Error(`slide ${slideNumber} is not wired into presentation.xml.rels (corrupt deck?)`);
10178
10174
  const rId = /Id="(rId\d+)"/.exec(relMatch)?.[1];
@@ -10180,19 +10176,19 @@ async function removePptxSlide(bytes, slideNumber) {
10180
10176
  throw new Error(`slide ${slideNumber}'s relationship carries no Id (corrupt deck?)`);
10181
10177
  zip.file(presRelsPath, presRels.replace(relMatch, ""));
10182
10178
  const presPath = "ppt/presentation.xml";
10183
- const pres = await text2(zip, presPath);
10179
+ const pres = await text3(zip, presPath);
10184
10180
  const sld = removeElement(pres, "p:sldId", (el) => el.includes(`r:id="${rId}"`));
10185
10181
  if (!sld.removed)
10186
10182
  throw new Error(`slide ${slideNumber} (${rId}) not found in the slide list (corrupt deck?)`);
10187
10183
  zip.file(presPath, sld.xml);
10188
- const slideRels = zip.file(relsPath) ? await text2(zip, relsPath) : "";
10184
+ const slideRels = zip.file(relsPath) ? await text3(zip, relsPath) : "";
10189
10185
  const notesTarget = /<Relationship\b[^>]*Type="[^"]*\/notesSlide"[^>]*Target="\.\.\/(notesSlides\/notesSlide\d+\.xml)"/.exec(slideRels)?.[1];
10190
10186
  const removedParts = [xmlPath, relsPath];
10191
10187
  if (notesTarget) {
10192
10188
  const otherSlideRels = Object.keys(zip.files).filter((p) => /^ppt\/slides\/_rels\/slide\d+\.xml\.rels$/.test(p) && p !== relsPath);
10193
10189
  let shared = false;
10194
10190
  for (const p of otherSlideRels) {
10195
- if ((await text2(zip, p)).includes(notesTarget)) {
10191
+ if ((await text3(zip, p)).includes(notesTarget)) {
10196
10192
  shared = true;
10197
10193
  break;
10198
10194
  }
@@ -10200,7 +10196,7 @@ async function removePptxSlide(bytes, slideNumber) {
10200
10196
  if (!shared)
10201
10197
  removedParts.push(`ppt/${notesTarget}`, `ppt/notesSlides/_rels/${notesTarget.split("/")[1]}.rels`);
10202
10198
  }
10203
- let ct = await text2(zip, "[Content_Types].xml");
10199
+ let ct = await text3(zip, "[Content_Types].xml");
10204
10200
  for (const part of removedParts) {
10205
10201
  zip.remove(part);
10206
10202
  ct = removeElement(ct, "Override", (el) => el.includes(`PartName="/${part}"`)).xml;
@@ -88,21 +88,37 @@ pages). The required roles are a HARD checklist — Phase 2 must include them al
88
88
 
89
89
  | 场景 | 语气 | 密度 | 必备章节(required roles — all MUST appear) | 叙事(Phase 2) | 默认页数 |
90
90
  |---|---|---|---|---|---|
91
- | **pitch** 融资/路演 | 自信 · 有张力 · 故事驱动 | 稀疏 · 大数字 | Problem · Solution · Market · Product/Traction · Team · **Ask** | SCQA / 问题-方案 | 10–12 |
91
+ | **pitch** 融资/路演 | 自信 · 有张力 · 故事驱动 | 稀疏 · 大数字 | Problem/问题 · Solution/解决方案 · Market/市场 · Product/Traction/产品/进展 · Team/团队 · **Ask/融资需求** | SCQA / 问题-方案 | 10–12 |
92
92
  | **内审** | 客观 · 直接 · 结论先行 | 略密(容明细/数据) | 结论/进展 · 关键指标 · 问题与风险 · 下一步/决策项 | 结论先行 | 6–8 |
93
- | **销售** | 利益驱动 · 客户中心 · 说服 | 中 · 重价值与佐证 | 痛点 · 方案/价值主张 · 差异化 · 客户案例 · ROI/定价 · **CTA** | 问题-方案 | 8–12 |
93
+ | **销售** | 利益驱动 · 客户中心 · 说服 | 中 · 重价值与佐证 | 痛点 · 方案/价值主张 · 差异化 · 客户案例 · ROI/定价 · **CTA/行动号召** | 问题-方案 | 8–12 |
94
94
  | **讲座** 学术 | 讲解 · 循序渐进 | 中 · 概念+例子 | 学习目标 · 背景/基础 · 核心概念 · 案例/推导 · 小结 | 由浅入深 | 10–15 |
95
- | **发布会** keynote | 情绪化 · 戏剧性 · 揭晓感 | **极稀疏 · 一页一信息 · 超大视觉** | 钩子 · 背景/痛点 · 产品揭晓 · 亮点特性 · Demo · 价格上市 · **行动号召** | 情绪线 | 15–20 |
96
- | **培训** | 教学 · 清晰 · 可操作 | 中 · 分模块 | Objectives · Modules · 练习/示例 · Quiz · Summary | 由浅入深 | 8–15 |
95
+ | **发布会** keynote | 情绪化 · 戏剧性 · 揭晓感 | **极稀疏 · 一页一信息 · 超大视觉** | 钩子 · 背景/痛点 · 产品揭晓 · 亮点特性 · Demo/演示 · 价格上市 · **行动号召** | 情绪线 | 15–20 |
96
+ | **培训** | 教学 · 清晰 · 可操作 | 中 · 分模块 | Objectives/学习目标 · Module/课程模块 · 练习/示例/Exercise · Quiz/随堂测验 · Summary/小结 | 由浅入深 | 8–15 |
97
97
  | **大会** talk | 观点鲜明 · 启发 · 记忆点 | 稀疏 · 一图一句 | 开场钩子 · 核心论点 · 论据/案例 · 反直觉洞察 · 收束记忆点 | 情绪线 / SCQA | 15–20 |
98
98
  | **工作汇报** 周月季报 | 客观 · 简洁 · 结论先行 | 中 | 概要 · 进展/成果 · 数据指标 · 问题 · 下一步计划 | 结论先行 | 5–10 |
99
- | **述职/晋升** | 自信 · 有据 · 个人视角 | 中 | 职责概述 · 关键成果(STAR)· 数据佐证 · 能力成长 · 规划 | 结论先行 | 8–12 |
99
+ | **述职/晋升** | 自信 · 有据 · 个人视角 | 中 | 职责概述 · 关键成果/STAR · 数据佐证 · 能力成长 · 规划 | 结论先行 | 8–12 |
100
100
  | **项目立项/评审** | 严谨 · 说服 | 中偏密 | 背景/痛点 · 目标 · 方案 · 计划/里程碑 · 资源/预算 · 风险 | 问题-方案 | 8–14 |
101
101
  | **年度总结/年会** | 振奋 · 仪式感 | 稀疏 · 大视觉 | 回顾/高光 · 关键数据 · 里程碑 · 团队 · 来年展望 | 情绪线 | 12–20 |
102
102
  | **商业计划书** BP | 自信 · 全面 · 数据支撑 | 中偏密 | 问题 · 方案 · 市场 · 产品 · 商业模式 · 竞争 · 财务预测 · 团队 · **融资** | SCQA | 15–25 |
103
103
  | **投标** 招投标 | 正式 · 要素齐全 · 得分导向 | 密 | 需求理解 · 方案 · 团队/资质 · 案例业绩 · 实施计划 · **报价** · 售后 | 结论先行 | 15–30 |
104
104
  | **政务/党政汇报** | 严肃 · 规范 | 中偏密 | 背景/依据 · 工作举措 · 成效数据 · 存在问题 · 下步部署 | 结论先行 | 8–15 |
105
105
  | **公司/产品介绍** | 品牌 · 自信 · 利益导向 | 中 · 重视觉 | 公司/愿景 · 核心能力 · 产品/方案 · 标杆案例 · 数据 · 合作邀请 | 问题-方案 | 8–15 |
106
+ | **产品调研** 竞品分析 市场研究 | 客观 · 有据 · 不替结论下判断 | 中 | 市场规模 · 竞品格局 · 用户需求 · 差距与机会 · 结论建议 | 先摆事实,再给判断 | 10–15 |
107
+ | **会议纪要** 会后同步 | 简洁 · 可执行 · 不复述过程 | 低 | 议题 · 结论 · 待办 · 待决事项 | 结论先行 | 4–8 |
108
+ | **数据分析** 数据解读 指标复盘 | 结论先行 · 可追溯 | 中 | 结论 · 口径与数据源 · 维度拆解 · 归因 · 建议 | 结论先行 | 6–10 |
109
+
110
+ **必备章节要中英双写(`English/中文`)。** 这张 checklist 的用法是拿每个词去**生成
111
+ 出来的大纲标题**里找子串(斜杠分段,命中任意一段就算有)。写成纯英文时,一份写得
112
+ 好好的中文稿一个都命中不了 —— 于是每次都判缺、每次都白花一轮模型回喂(10–30 秒
113
+ +一次调用的钱)。反过来整行换成中文也不对:中文路演稿**真的**会写 Problem / Ask /
114
+ Demo,换掉只是把漏判翻到另一边。中文那半边要挑够窄的词:写「融资」的话,一张叫
115
+ 「我们的融资故事」的封面就能把 Ask 顶掉,而那一节缺了正是这张表存在的理由。
116
+ 括号写法(`关键成果(STAR)`)同样不行 —— 它一个斜杠都没有,整串当一个词去找,
117
+ 大纲里必须原样出现那七个字符才算命中。
118
+
119
+ 还有两个容易漏的:**用单数**(大纲会写 `Module 1`,`Modules` 匹配不上,而 `Module`
120
+ 两种都命中);**本来就是中文的那几段也要补英文**(`练习/示例` 漏了 `Exercise`,
121
+ 一份英文培训大纲就在这一项上判缺)。
106
122
 
107
123
  Tone also biases the catalog style ranking: 张力/情绪(pitch·发布会·大会)→ 深色酷炫(cool/apple/
108
124
  black-gold);务实(内审·销售)→ 白底咨询(mckinsey);清晰(讲座·培训)→ 中性/教育风.
@@ -131,6 +147,39 @@ Search 8–12 queries across layers, then organize into 6 dimensions:
131
147
 
132
148
  Dimensions: 概述 / 背景 / 关键信息 / 证据(案例·数据) / 分析 / 展望.
133
149
 
150
+ **层次是兜底,场景才是方向。** 上面那五层是**开放式议题**的默认铺法(用户只给了
151
+ 一个主题、没有材料)。一旦 Phase 0 选定了场景,就照下表按**这份稿子真正需要的东西**
152
+ 去查 —— 每条焦点出 1–2 条查询词,再从上面五层补 2–4 条防止十条围着一个角度。
153
+ 用户在 Phase 0 自己交代的那句话优先级最高,先查他明说要的。
154
+
155
+ 焦点直接对着上面场景矩阵的 `必备章节` —— 查回来的东西要能填进那些章节,
156
+ 否则这一轮检索就是白花的(按次计费)。
157
+
158
+ | 场景 | 检索焦点 |
159
+ |---|---|
160
+ | **pitch** 融资/路演 | 市场规模与增速(TAM/SAM) · 可比公司融资与估值 · 同类产品与差异 · 目标客群痛点证据 |
161
+ | **内审** | 行业对标指标 · 口径定义 · 外部风险事件 |
162
+ | **销售** | 客户所在行业痛点 · 竞品方案与差异 · 同行落地案例与 ROI · 公开定价 |
163
+ | **讲座** 学术 | 概念定义与权威教材 · 关键论文与综述 · 经典案例/推导 · 常见误解 |
164
+ | **发布会** keynote | 同类产品痛点与差评 · 竞品参数对比 · 竞品定价与上市节奏 · 可引用的用户场景 |
165
+ | **培训** | 权威教程与标准 · 分步操作示例 · 常见错误与排错 · 练习题与考点 |
166
+ | **大会** talk | 反直觉数据与研究 · 争议观点与反例 · 一手案例/失败教训 · 可引用金句 |
167
+ | **工作汇报** 周月季报 | 行业基准与同行数据 · 指标口径定义 · 外部环境变化 |
168
+ | **述职/晋升** | 同岗位能力模型 · 行业对标数据 · 该领域公认的成果衡量口径 |
169
+ | **项目立项/评审** | 同类项目投入产出 · 技术方案与选型对比 · 合规与风险案例 · 人力/预算基准 |
170
+ | **年度总结/年会** | 行业年度大事 · 同行里程碑对照 · 来年趋势预测 |
171
+ | **商业计划书** BP | 市场规模与分层 · 竞争格局与份额 · 商业模式与单位经济 · 可比公司财务与融资 |
172
+ | **投标** 招投标 | 招标方背景与既往采购 · 评分办法与资质要求 · 同类中标公告与报价区间 · 标杆案例 |
173
+ | **政务/党政汇报** | 政策文件与依据原文 · 上级部署口径 · 同级地区做法 · 公开统计数据 |
174
+ | **公司/产品介绍** | 行业地位与第三方报告 · 竞品对比 · 可公开引用的客户案例 · 行业趋势 |
175
+ | **产品调研** 竞品分析 市场研究 | 市场规模与增速 · 竞品功能与定价对比 · 用户评价与差评 · 渠道与份额数据 |
176
+ | **会议纪要** 会后同步 | 议题涉及的外部事实 · 相关口径与定义 · 同类决策的公开先例 |
177
+ | **数据分析** 数据解读 指标复盘 | 指标口径定义 · 行业基准值 · 同类归因案例与方法 |
178
+
179
+ 内部数据型的几档(内审 · 述职 · 工作汇报 · 年度总结)焦点**刻意收窄到对标与口径**:
180
+ 它们的主体材料在用户自己手里,联网能补的只有"外面是什么水位"。照五层去查行业定义
181
+ 和历史,查回来的东西一条都填不进它们的必备章节。
182
+
134
183
  **Fan out, then cite:** run layers in PARALLEL (many searches at once, or a
135
184
  sub-agent per dimension) — breadth beats depth-first. **Every data point
136
185
  (number/percent/year/quote) carries its source** — keep a `{claim → URL}` list; a
@@ -61,6 +61,14 @@ figure row missing its numbers — **fails the build** (exit 1, nothing written)
61
61
  shipping the template's demo content. Regenerate the index with `node scripts/deck/gen-slots.mjs`
62
62
  after touching a `.tpl`.
63
63
 
64
+ **不要给可变内容写死容器高度。** `.card{height:…px}` 这类写法在皮肤给 `.card` 设了
65
+ `overflow:hidden` 时会把超出的文字**静默裁掉**(`blocks-2x2` 就这么带着缺陷出厂过)。
66
+ 让高度由内容决定:网格用 `grid-auto-rows:min-content`(下限必须显式写 `min-content` ——
67
+ `1fr`/`auto` 的自动下限对 `overflow` 非 visible 的网格项一律归零),余量交给外层
68
+ `justify-content:space-between`。这样内容超量时会把后续元素顶出页面,被 `deck-qa` 的
69
+ `off-canvas`/`overlap` 抓到,而不是变成一排缺了下半截的字。`deck-qa` 的第三条硬失败
70
+ `clipped` 专门守这件事,并且对**整册版式库**逐个版式扫,不只是 `sweep-spec.json` 里那几个。
71
+
64
72
  ## Catalog
65
73
 
66
74
  Each slide carries `data-layout="<id>"` (drives the diversity lint + traceability).
@@ -1,19 +1,29 @@
1
1
  <!-- layouts/blocks-2x2 — structure-only (paint via styles/<skin>/skin.css). 招牌"2×2 大色块 + 引言条":标题 + 两段引子 + 四个大编号块(skin 决定实色/柔彩/描边)+ 底部引言条 + 参考框. data-layout drives P1/P2/P3 + dedup. -->
2
+ <!-- 引子/色块/引言条走一条 flex 纵向流(.blocks-flow),卡片不再写死高度 —— `.card` 曾是
3
+ `height:118px`,而卡内 26px padding + 34px 编号 + 22px 标题 + 14px 正文实际要 148–178px,
4
+ 12 个把 `.card` 设成 overflow:hidden 的族因此把正文最后一行拦腰切断(deck-qa-sweep 的
5
+ `clipped` 判据守的就是它)。现在行高 `min-content` 咬死内容,
6
+ 余量由 `justify-content:space-between` 分给引子与引言条之间 —— 内容再长也只会把引言条
7
+ 顶向页脚(闸门报 off-canvas/overlap),不会静默裁字。下限必须写成显式的 `min-content`:
8
+ `1fr`/`auto` 的自动下限对 `overflow:hidden` 的网格项一律归零,而 `.card` 的 overflow
9
+ 恰恰是皮肤设的 —— 写 `1fr` 等于没有下限,卡片照样会被压扁再裁字。 -->
2
10
  <section class="slide" data-layout="blocks-2x2" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div>
3
11
 
4
12
 
5
13
  <div class="eyebrow-row" style="position:absolute;left:calc(96px * var(--space-scale,1));top:124px;display:flex;align-items:center;gap:14px"><span class="accent-bar" style="width:30px;height:1px;display:inline-block"></span><span class="eyebrow" style="font-size:calc(13px * var(--type-scale,1));letter-spacing:.28em">{{eyebrow|PRINCIPLES}}</span></div>
6
14
  <h2 class="deck-title" style="position:absolute;left:calc(92px * var(--space-scale,1));top:146px;font-size:calc(42px * var(--type-scale,1));letter-spacing:-.4px">{{title|章节主标题}}</h2>
7
- <p class="card-body" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:214px;font-size:calc(16px * var(--type-scale,1));line-height:1.7">{{intro|一段引子说明,两三行,交代这一章的核心观点与背景,替换为真实内容。承接标题,引出下面四个要点。}}</p>
8
- <div class="card-grid" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:296px;display:grid;grid-template-columns:1fr 1fr;gap:20px">
9
- <div class="card" style="position:relative;padding:26px 30px;height:118px"><span class="card-rail" style="position:absolute;left:0;top:24px;width:3px;height:40px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(34px * var(--type-scale,1));font-weight:800;line-height:1">01</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:6px">{{block1_title|要点一标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:6px">{{block1_body|一句说明,替换为真实内容。}}</p></div>
10
- <div class="card" style="position:relative;padding:26px 30px;height:118px"><span class="card-rail" style="position:absolute;left:0;top:24px;width:3px;height:40px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(34px * var(--type-scale,1));font-weight:800;line-height:1">02</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:6px">{{block2_title|要点二标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:6px">{{block2_body|一句说明,替换为真实内容。}}</p></div>
11
- <div class="card" style="position:relative;padding:26px 30px;height:118px"><span class="card-rail" style="position:absolute;left:0;top:24px;width:3px;height:40px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(34px * var(--type-scale,1));font-weight:800;line-height:1">03</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:6px">{{block3_title|要点三标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:6px">{{block3_body|一句说明,替换为真实内容。}}</p></div>
12
- <div class="card" style="position:relative;padding:26px 30px;height:118px"><span class="card-rail" style="position:absolute;left:0;top:24px;width:3px;height:40px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(34px * var(--type-scale,1));font-weight:800;line-height:1">04</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:6px">{{block4_title|要点四标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:6px">{{block4_body|一句说明,替换为真实内容。}}</p></div>
15
+ <div class="blocks-flow" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:212px;bottom:62px;display:flex;flex-direction:column;justify-content:space-between;gap:14px">
16
+ <p class="card-body" style="flex:none;font-size:calc(16px * var(--type-scale,1));line-height:1.7">{{intro|一段引子说明,两三行,交代这一章的核心观点与背景,替换为真实内容。承接标题,引出下面四个要点。}}</p>
17
+ <div class="card-grid" style="flex:none;display:grid;grid-template-columns:1fr 1fr;grid-auto-rows:min-content;gap:16px">
18
+ <div class="card" style="position:relative;padding:16px 26px"><span class="card-rail" style="position:absolute;left:0;top:20px;width:3px;height:34px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(26px * var(--type-scale,1));font-weight:800;line-height:1">01</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:4px">{{block1_title|要点一标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{block1_body|一句说明,替换为真实内容。}}</p></div>
19
+ <div class="card" style="position:relative;padding:16px 26px"><span class="card-rail" style="position:absolute;left:0;top:20px;width:3px;height:34px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(26px * var(--type-scale,1));font-weight:800;line-height:1">02</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:4px">{{block2_title|要点二标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{block2_body|一句说明,替换为真实内容。}}</p></div>
20
+ <div class="card" style="position:relative;padding:16px 26px"><span class="card-rail" style="position:absolute;left:0;top:20px;width:3px;height:34px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(26px * var(--type-scale,1));font-weight:800;line-height:1">03</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:4px">{{block3_title|要点三标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{block3_body|一句说明,替换为真实内容。}}</p></div>
21
+ <div class="card" style="position:relative;padding:16px 26px"><span class="card-rail" style="position:absolute;left:0;top:20px;width:3px;height:34px;border-radius:2px"></span><span class="card-idx" style="font-size:calc(26px * var(--type-scale,1));font-weight:800;line-height:1">04</span><div class="card-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;margin-top:4px">{{block4_title|要点四标题}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{block4_body|一句说明,替换为真实内容。}}</p></div>
22
+ </div>
23
+ <div style="flex:none;display:flex;gap:18px">
24
+ <div class="quote-bar" style="flex:1.7;padding:14px 22px;border-radius:var(--card-radius)"><div class="quote-txt" style="font-size:calc(17px * var(--type-scale,1));font-weight:700">{{quote|"一句金句,点睛这一章。"}}</div><div class="quote-attr" style="font-size:calc(13px * var(--type-scale,1));margin-top:4px">{{quote_attr|— 出处 / 作者}}</div></div>
25
+ <div class="footnote" style="flex:1;padding:14px 20px;border-radius:var(--card-radius)"><span class="footnote-label" style="font-size:calc(12px * var(--type-scale,1));font-weight:700">参考资料:</span><span class="footnote-body" style="font-size:calc(12px * var(--type-scale,1))"> {{refs|来源一;来源二}}</span></div>
13
26
  </div>
14
- <div style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:76px;display:flex;gap:18px">
15
- <div class="quote-bar" style="flex:1.7;padding:18px 24px;border-radius:var(--card-radius)"><div class="quote-txt" style="font-size:calc(17px * var(--type-scale,1));font-weight:700">{{quote|"一句金句,点睛这一章。"}}</div><div class="quote-attr" style="font-size:calc(13px * var(--type-scale,1));margin-top:4px">{{quote_attr|— 出处 / 作者}}</div></div>
16
- <div class="footnote" style="flex:1;padding:16px 20px;border-radius:var(--card-radius)"><span class="footnote-label" style="font-size:calc(12px * var(--type-scale,1));font-weight:700">参考资料:</span><span class="footnote-body" style="font-size:calc(12px * var(--type-scale,1))"> {{refs|来源一;来源二}}</span></div>
17
27
  </div>
18
28
  <div class="rule rule-foot" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1));letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1))">{{pageno|01}}</div>
19
29
  </section>
@@ -1,4 +1,4 @@
1
1
  <!-- layouts/cards-3 — structure-only (paint via styles/<skin>/skin.css). data-layout drives P1/P2/P3 + dedup. -->
2
2
  <section class="slide" data-layout="cards-3" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:calc(96px * var(--space-scale,1));top:132px;display:flex;align-items:center;gap:14px"><span class="accent-bar" style="width:30px;height:1px;display:inline-block"></span><span class="eyebrow" style="font-size:calc(13px * var(--type-scale,1));letter-spacing:.28em">{{eyebrow|OVERVIEW}}</span></div><h2 class="deck-title" style="position:absolute;left:calc(92px * var(--space-scale,1));top:158px;font-size:calc(48px * var(--type-scale,1));letter-spacing:-.4px">{{title|三个要点}}</h2>
3
- <div class="card-grid" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:290px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:24px"><div class="card" style="position:relative;padding:32px 34px;height:300px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">01</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card1_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card1_body|一句说明,替换为真实内容。}}</p></div><div class="card" style="position:relative;padding:32px 34px;height:300px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">02</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card2_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card2_body|一句说明,替换为真实内容。}}</p></div><div class="card" style="position:relative;padding:32px 34px;height:300px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">03</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card3_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card3_body|一句说明,替换为真实内容。}}</p></div></div>
3
+ <div class="card-grid" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:290px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:24px"><div class="card" style="position:relative;padding:32px 34px;min-height:180px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">01</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card1_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card1_body|一句说明,替换为真实内容。}}</p></div><div class="card" style="position:relative;padding:32px 34px;min-height:180px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">02</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card2_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card2_body|一句说明,替换为真实内容。}}</p></div><div class="card" style="position:relative;padding:32px 34px;min-height:180px"><span class="card-rail" style="position:absolute;left:0;top:28px;width:3px;height:40px;border-radius:2px"></span><div style="display:flex;align-items:center;gap:10px"><span class="card-dot" style="width:7px;height:7px;border-radius:50%;display:inline-block"></span><span class="card-idx" style="font-size:calc(12px * var(--type-scale,1));letter-spacing:.2em">03</span></div><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700;margin-top:14px">{{card3_title|要点标题}}</div><p class="card-body" style="font-size:calc(15.5px * var(--type-scale,1));line-height:1.6;margin-top:10px">{{card3_body|一句说明,替换为真实内容。}}</p></div></div>
4
4
  <div class="rule rule-foot" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1));letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1))">{{pageno|01}}</div></section>
@@ -1,4 +1,4 @@
1
1
  <!-- layouts/org-tree — structure-only variant (paint via skin). -->
2
2
  <section class="slide" data-layout="org-tree" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:calc(96px * var(--space-scale,1));top:132px;display:flex;align-items:center;gap:14px"><span class="accent-bar" style="width:30px;height:1px;display:inline-block"></span><span class="eyebrow" style="font-size:calc(13px * var(--type-scale,1));letter-spacing:.28em">{{eyebrow|STRUCTURE}}</span></div><h2 class="deck-title" style="position:absolute;left:calc(92px * var(--space-scale,1));top:158px;font-size:calc(48px * var(--type-scale,1));letter-spacing:-.4px">{{title|组织架构}}</h2>
3
- <svg width="1280" height="720" viewBox="0 0 1280 720" style="position:absolute;inset:0;pointer-events:none"><g class="hub-link" fill="none" stroke-width="1.5"><line x1="640" y1="352" x2="640" y2="416"/><line x1="300" y1="416" x2="980" y2="416"/><line x1="300" y1="416" x2="300" y2="452"/><line x1="640" y1="416" x2="640" y2="452"/><line x1="980" y1="416" x2="980" y2="452"/></g></svg><div class="card" style="position:absolute;left:520px;top:290px;width:240px;height:62px;display:flex;align-items:center;justify-content:center"><div class="card-title" style="font-size:calc(20px * var(--type-scale,1));font-weight:700">{{top|最高负责人}}</div></div><div class="card" style="position:absolute;left:180px;top:452px;width:240px;height:150px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept1_title|技术部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept1_body|职能一句说明。}}</p></div><div class="card" style="position:absolute;left:520px;top:452px;width:240px;height:150px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept2_title|产品部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept2_body|职能一句说明。}}</p></div><div class="card" style="position:absolute;left:860px;top:452px;width:240px;height:150px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept3_title|运营部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept3_body|职能一句说明。}}</p></div>
3
+ <svg width="1280" height="720" viewBox="0 0 1280 720" style="position:absolute;inset:0;pointer-events:none"><g class="hub-link" fill="none" stroke-width="1.5"><line x1="640" y1="352" x2="640" y2="416"/><line x1="300" y1="416" x2="980" y2="416"/><line x1="300" y1="416" x2="300" y2="452"/><line x1="640" y1="416" x2="640" y2="452"/><line x1="980" y1="416" x2="980" y2="452"/></g></svg><div class="card" style="position:absolute;left:520px;top:290px;width:240px;height:62px;display:flex;align-items:center;justify-content:center"><div class="card-title" style="font-size:calc(20px * var(--type-scale,1));font-weight:700">{{top|最高负责人}}</div></div><div class="card" style="position:absolute;left:180px;top:452px;width:240px;min-height:96px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept1_title|技术部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept1_body|职能一句说明。}}</p></div><div class="card" style="position:absolute;left:520px;top:452px;width:240px;min-height:96px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept2_title|产品部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept2_body|职能一句说明。}}</p></div><div class="card" style="position:absolute;left:860px;top:452px;width:240px;min-height:96px;padding:22px"><div class="card-title" style="font-size:calc(18px * var(--type-scale,1));font-weight:700">{{dept3_title|运营部}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.5;margin-top:8px">{{dept3_body|职能一句说明。}}</p></div>
4
4
  <div class="rule rule-foot" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1));letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1))">{{pageno|01}}</div></section>
@@ -1,4 +1,4 @@
1
1
  <!-- layouts/steps-vertical — structure-only variant (paint via skin). rows.steps{name,body} — the numbered circle uses the row index ({{_n}}); the connector line spans the list, so 3–5 steps all sit right. -->
2
2
  <section class="slide" data-layout="steps-vertical" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:calc(96px * var(--space-scale,1));top:132px;display:flex;align-items:center;gap:14px"><span class="accent-bar" style="width:30px;height:1px;display:inline-block"></span><span class="eyebrow" style="font-size:calc(13px * var(--type-scale,1));letter-spacing:.28em">{{eyebrow|PROCESS}}</span></div><h2 class="deck-title" style="position:absolute;left:calc(92px * var(--space-scale,1));top:158px;font-size:calc(48px * var(--type-scale,1));letter-spacing:-.4px">{{title|实施步骤}}</h2>
3
- <div style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:290px;display:flex;flex-direction:column;gap:20px"><div class="step-line" style="position:absolute;left:62px;top:41px;bottom:41px;width:2px"></div>{{#steps}}<div style="position:relative;display:flex;align-items:center;gap:28px;height:82px"><div class="step-circle" style="width:64px;height:64px;border-radius:50%;flex:0 0 auto;display:flex;align-items:center;justify-content:center;text-align:center;line-height:1;font-size:calc(26px * var(--type-scale,1));font-weight:700">{{_n|1}}</div><div><div class="step-title" style="font-size:calc(21px * var(--type-scale,1));font-weight:700">{{name|占位步骤}}</div><p class="step-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{body|一句说明,替换为真实内容。}}</p></div></div>{{/steps}}</div>
3
+ <div style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:290px;display:flex;flex-direction:column;gap:20px"><div class="step-line" style="position:absolute;left:31px;top:41px;bottom:41px;width:2px"></div>{{#steps}}<div style="position:relative;display:flex;align-items:center;gap:28px;height:82px"><div class="step-circle" style="width:64px;height:64px;border-radius:50%;flex:0 0 auto;display:flex;align-items:center;justify-content:center;text-align:center;line-height:1;font-size:calc(26px * var(--type-scale,1));font-weight:700">{{_n|1}}</div><div><div class="step-title" style="font-size:calc(21px * var(--type-scale,1));font-weight:700">{{name|占位步骤}}</div><p class="step-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.5;margin-top:4px">{{body|一句说明,替换为真实内容。}}</p></div></div>{{/steps}}</div>
4
4
  <div class="rule rule-foot" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1));letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1))">{{pageno|01}}</div></section>