@taloswork/ose-shared 0.1.1 → 0.1.3

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 (160) hide show
  1. package/package.json +3 -3
  2. package/skills/document/SKILL.md +29 -33
  3. package/skills/document/assets/fonts/Archivo-Regular.woff2 +0 -0
  4. package/skills/document/assets/fonts/Archivo-SemiBold.woff2 +0 -0
  5. package/skills/document/assets/fonts/BigShouldersDisplay-Bold.woff2 +0 -0
  6. package/skills/document/assets/fonts/BodoniModa-SemiBold.woff2 +0 -0
  7. package/skills/document/assets/fonts/CormorantGaramond-SemiBold.woff2 +0 -0
  8. package/skills/document/assets/fonts/Fraunces-SemiBold.woff2 +0 -0
  9. package/skills/document/assets/fonts/GochiHand-Regular.woff2 +0 -0
  10. package/skills/document/assets/fonts/IBMPlexSans-Regular.woff2 +0 -0
  11. package/skills/document/assets/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
  12. package/skills/document/assets/fonts/Inter-Regular.woff2 +0 -0
  13. package/skills/document/assets/fonts/Jost-Regular.woff2 +0 -0
  14. package/skills/document/assets/fonts/Jost-SemiBold.woff2 +0 -0
  15. package/skills/document/assets/fonts/Karla-Regular.woff2 +0 -0
  16. package/skills/document/assets/fonts/Lora-Regular.woff2 +0 -0
  17. package/skills/document/assets/fonts/Manrope-Bold.woff2 +0 -0
  18. package/skills/document/assets/fonts/Manrope-Regular.woff2 +0 -0
  19. package/skills/document/assets/fonts/Marcellus-Regular.woff2 +0 -0
  20. package/skills/document/assets/fonts/PublicSans-Regular.woff2 +0 -0
  21. package/skills/document/assets/fonts/Sora-Regular.woff2 +0 -0
  22. package/skills/document/assets/fonts/Sora-SemiBold.woff2 +0 -0
  23. package/skills/document/assets/fonts/fonts.json +218 -0
  24. package/skills/document/bin/deck-build.cjs +275 -7
  25. package/skills/document/bin/deck-qa.cjs +1 -1
  26. package/skills/document/bin/doc-convert.cjs +11 -11
  27. package/skills/document/bin/doc-fill.cjs +1 -1
  28. package/skills/document/bin/doc-gen.cjs +119 -34
  29. package/skills/document/bin/doc-scan.cjs +8 -10
  30. package/skills/document/bin/doc-text.cjs +1 -1
  31. package/skills/document/bin/doc-validate.cjs +3 -3
  32. package/skills/document/bin/doc-xml.cjs +3 -3
  33. package/skills/document/bin/docx-annotate.cjs +3 -3
  34. package/skills/document/bin/html2pptx.cjs +290 -59
  35. package/skills/document/bin/ocr.cjs +1 -1
  36. package/skills/document/bin/pdf-form.cjs +1 -1
  37. package/skills/document/bin/pdf-images.cjs +1 -1
  38. package/skills/document/bin/pdf-ops.cjs +2 -2
  39. package/skills/document/bin/pdf-render.cjs +1 -1
  40. package/skills/document/bin/pdf-tables.cjs +1 -1
  41. package/skills/document/bin/pptx-clone.cjs +3 -3
  42. package/skills/document/bin/pptx-embed-fonts.cjs +1 -1
  43. package/skills/document/bin/pptx-set-image.cjs +3 -3
  44. package/skills/document/bin/pptx-slide.cjs +4 -4
  45. package/skills/document/bin/pptx-theme.cjs +1 -1
  46. package/skills/document/bin/pptx-tokenize.cjs +3 -3
  47. package/skills/document/bin/xlsx-query.cjs +1 -1
  48. package/skills/document/bin/xlsx-recalc.cjs +2 -2
  49. package/skills/document/catalog.json +25 -0
  50. package/skills/document/deck-design.md +191 -0
  51. package/skills/document/layouts/README.md +32 -0
  52. package/skills/document/layouts/banner-columns.tpl +9 -9
  53. package/skills/document/layouts/bento.tpl +3 -3
  54. package/skills/document/layouts/big-stat.tpl +3 -3
  55. package/skills/document/layouts/blocks-2x2.tpl +12 -12
  56. package/skills/document/layouts/brand-values.tpl +5 -5
  57. package/skills/document/layouts/cards-3.tpl +3 -3
  58. package/skills/document/layouts/cards-grid.tpl +3 -3
  59. package/skills/document/layouts/chart-full.tpl +3 -3
  60. package/skills/document/layouts/chart-kpi.tpl +3 -3
  61. package/skills/document/layouts/color-palette.tpl +5 -5
  62. package/skills/document/layouts/comparison.tpl +3 -3
  63. package/skills/document/layouts/concept-hub.tpl +3 -3
  64. package/skills/document/layouts/cover-centered.tpl +1 -1
  65. package/skills/document/layouts/cover-image.tpl +1 -1
  66. package/skills/document/layouts/cover-minimal.tpl +3 -3
  67. package/skills/document/layouts/cover-statement.tpl +3 -3
  68. package/skills/document/layouts/cover.tpl +1 -1
  69. package/skills/document/layouts/data-table.tpl +3 -3
  70. package/skills/document/layouts/dos-donts.tpl +14 -14
  71. package/skills/document/layouts/editorial-panel.tpl +11 -11
  72. package/skills/document/layouts/ending-contact.tpl +1 -1
  73. package/skills/document/layouts/ending.tpl +1 -1
  74. package/skills/document/layouts/funnel.tpl +3 -3
  75. package/skills/document/layouts/gantt.tpl +3 -3
  76. package/skills/document/layouts/hero.tpl +3 -3
  77. package/skills/document/layouts/icon-row.tpl +3 -3
  78. package/skills/document/layouts/image-full.tpl +5 -5
  79. package/skills/document/layouts/image-grid.tpl +3 -3
  80. package/skills/document/layouts/image-left.tpl +3 -3
  81. package/skills/document/layouts/list.tpl +3 -3
  82. package/skills/document/layouts/logo-guidelines.tpl +8 -8
  83. package/skills/document/layouts/map-distribution.tpl +3 -3
  84. package/skills/document/layouts/map-quad.tpl +6 -6
  85. package/skills/document/layouts/matrix-2x2.tpl +3 -3
  86. package/skills/document/layouts/numbered-brief.tpl +12 -12
  87. package/skills/document/layouts/org-tree.tpl +3 -3
  88. package/skills/document/layouts/problem-solution-banner.tpl +7 -7
  89. package/skills/document/layouts/problem-solution.tpl +3 -3
  90. package/skills/document/layouts/pyramid.tpl +3 -3
  91. package/skills/document/layouts/quote.tpl +1 -1
  92. package/skills/document/layouts/radar.tpl +3 -3
  93. package/skills/document/layouts/ring-progress.tpl +3 -3
  94. package/skills/document/layouts/section-fullbleed.tpl +3 -3
  95. package/skills/document/layouts/section-image.tpl +1 -1
  96. package/skills/document/layouts/section-stat.tpl +1 -1
  97. package/skills/document/layouts/section.tpl +1 -1
  98. package/skills/document/layouts/slots.json +1 -1
  99. package/skills/document/layouts/split-two-col.tpl +3 -3
  100. package/skills/document/layouts/stats-chart.tpl +3 -3
  101. package/skills/document/layouts/steps-serpentine.tpl +11 -11
  102. package/skills/document/layouts/steps-vertical.tpl +3 -3
  103. package/skills/document/layouts/steps.tpl +3 -3
  104. package/skills/document/layouts/team-row.tpl +4 -4
  105. package/skills/document/layouts/three-kpi.tpl +3 -3
  106. package/skills/document/layouts/timeline.tpl +3 -3
  107. package/skills/document/layouts/title-meta.tpl +5 -5
  108. package/skills/document/layouts/title.tpl +2 -2
  109. package/skills/document/layouts/toc-agenda.tpl +3 -3
  110. package/skills/document/layouts/toc-editorial.tpl +15 -0
  111. package/skills/document/layouts/toc-panel.tpl +4 -4
  112. package/skills/document/layouts/toc.tpl +3 -3
  113. package/skills/document/layouts/transition.tpl +1 -1
  114. package/skills/document/layouts/two-kpi.tpl +3 -3
  115. package/skills/document/layouts/type-specimen.tpl +10 -10
  116. package/skills/document/layouts/versus.tpl +3 -3
  117. package/skills/document/motion/README.md +11 -0
  118. package/skills/document/packs/README.md +9 -0
  119. package/skills/document/styles/README.md +36 -15
  120. package/skills/document/styles/_contract-defaults.css +55 -0
  121. package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
  122. package/skills/document/styles/_samples/_groups/creative.webp +0 -0
  123. package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
  124. package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
  125. package/skills/document/styles/_samples/_groups/natural.webp +0 -0
  126. package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
  127. package/skills/document/styles/_samples/anthropic.webp +0 -0
  128. package/skills/document/styles/_samples/apple.webp +0 -0
  129. package/skills/document/styles/_samples/black-gold.webp +0 -0
  130. package/skills/document/styles/_samples/branding.webp +0 -0
  131. package/skills/document/styles/_samples/cinereel.webp +0 -0
  132. package/skills/document/styles/_samples/cool.webp +0 -0
  133. package/skills/document/styles/_samples/hand-drawn.webp +0 -0
  134. package/skills/document/styles/_samples/ivory-gold.webp +0 -0
  135. package/skills/document/styles/_samples/magazine-ink.webp +0 -0
  136. package/skills/document/styles/_samples/mckinsey.webp +0 -0
  137. package/skills/document/styles/_samples/mono.webp +0 -0
  138. package/skills/document/styles/_samples/olive-gold.webp +0 -0
  139. package/skills/document/styles/_samples/swiss-grid.webp +0 -0
  140. package/skills/document/styles/anthropic/backdrop.html +4 -0
  141. package/skills/document/styles/anthropic/skin.css +15 -8
  142. package/skills/document/styles/apple/backdrop.html +4 -1
  143. package/skills/document/styles/apple/skin.css +5 -2
  144. package/skills/document/styles/black-gold/backdrop.html +3 -0
  145. package/skills/document/styles/black-gold/skin.css +15 -8
  146. package/skills/document/styles/branding/backdrop.html +4 -0
  147. package/skills/document/styles/branding/skin.css +14 -7
  148. package/skills/document/styles/cinereel/skin.css +28 -10
  149. package/skills/document/styles/cool/backdrop.html +3 -0
  150. package/skills/document/styles/cool/skin.css +5 -2
  151. package/skills/document/styles/hand-drawn/skin.css +14 -6
  152. package/skills/document/styles/ivory-gold/skin.css +19 -6
  153. package/skills/document/styles/magazine-ink/skin.css +6 -1
  154. package/skills/document/styles/mckinsey/backdrop.html +5 -0
  155. package/skills/document/styles/mckinsey/skin.css +5 -2
  156. package/skills/document/styles/mono/backdrop.html +6 -0
  157. package/skills/document/styles/mono/skin.css +5 -2
  158. package/skills/document/styles/olive-gold/backdrop.html +5 -0
  159. package/skills/document/styles/olive-gold/skin.css +15 -8
  160. package/skills/document/styles/swiss-grid/skin.css +6 -1
@@ -9818,10 +9818,10 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/pptx-clone.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/pptx-clone.js
9821
+ // packages/core/dist/document/pptx-clone.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
 
9824
- // packages/core/dist/fs/ooxml-util.js
9824
+ // packages/core/dist/document/ooxml-util.js
9825
9825
  function escXml(s) {
9826
9826
  return s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[c]);
9827
9827
  }
@@ -9936,7 +9936,7 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
9936
9936
  return { xml: rewritten, count };
9937
9937
  }
9938
9938
 
9939
- // packages/core/dist/fs/pptx-clone.js
9939
+ // packages/core/dist/document/pptx-clone.js
9940
9940
  var SLIDE_CT = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
9941
9941
  var SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
9942
9942
  var EMU_PER_PT = 12700;
@@ -9818,7 +9818,7 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/pptx-embed-fonts.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/pptx-fonts.js
9821
+ // packages/core/dist/document/pptx-fonts.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
  var FONT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font";
9824
9824
  function escXml(s) {
@@ -9819,10 +9819,10 @@ var require_lib3 = __commonJS({
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
  var import_node_path = require("node:path");
9821
9821
 
9822
- // packages/core/dist/fs/pptx-set-image.js
9822
+ // packages/core/dist/document/pptx-set-image.js
9823
9823
  var import_jszip = __toESM(require_lib3(), 1);
9824
9824
 
9825
- // packages/core/dist/fs/ooxml-util.js
9825
+ // packages/core/dist/document/ooxml-util.js
9826
9826
  function elementRe(tag) {
9827
9827
  const t = tag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9828
9828
  return new RegExp(`<${t}\\b[^>]*(?:/>|>[\\s\\S]*?</${t}>)`, "g");
@@ -9835,7 +9835,7 @@ function findElement(xml, tag, test) {
9835
9835
  return void 0;
9836
9836
  }
9837
9837
 
9838
- // packages/core/dist/fs/pptx-set-image.js
9838
+ // packages/core/dist/document/pptx-set-image.js
9839
9839
  var CONTENT_TYPE = {
9840
9840
  png: "image/png",
9841
9841
  jpg: "image/jpeg",
@@ -9818,7 +9818,7 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/pptx-slide.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/pptx-slide.js
9821
+ // packages/core/dist/document/pptx-slide.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
  var SLIDE_CT = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
9824
9824
  var SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
@@ -9923,10 +9923,10 @@ async function reorderPptxSlides(bytes, order) {
9923
9923
  return { bytes: new Uint8Array(out2), order: [...order] };
9924
9924
  }
9925
9925
 
9926
- // packages/core/dist/fs/pptx-clone.js
9926
+ // packages/core/dist/document/pptx-clone.js
9927
9927
  var import_jszip2 = __toESM(require_lib3(), 1);
9928
9928
 
9929
- // packages/core/dist/fs/ooxml-util.js
9929
+ // packages/core/dist/document/ooxml-util.js
9930
9930
  function escXml(s) {
9931
9931
  return s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;" })[c]);
9932
9932
  }
@@ -10041,7 +10041,7 @@ function replaceTextAcrossRuns(xml, find, replacement, opts) {
10041
10041
  return { xml: rewritten, count };
10042
10042
  }
10043
10043
 
10044
- // packages/core/dist/fs/pptx-clone.js
10044
+ // packages/core/dist/document/pptx-clone.js
10045
10045
  var SLIDE_CT2 = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
10046
10046
  var SLIDE_REL_TYPE2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
10047
10047
  var EMU_PER_PT = 12700;
@@ -9818,7 +9818,7 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/pptx-theme.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/pptx-theme.js
9821
+ // packages/core/dist/document/pptx-theme.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
  var SYS_CLR = { windowText: "000000", window: "FFFFFF" };
9824
9824
  function schemeColor(clrScheme, slot) {
@@ -9818,10 +9818,10 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/pptx-tokenize.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/pptx-tokenize.js
9821
+ // packages/core/dist/document/pptx-tokenize.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
 
9824
- // packages/core/dist/fs/ooxml-util.js
9824
+ // packages/core/dist/document/ooxml-util.js
9825
9825
  function unescXml(s) {
9826
9826
  return s.replace(/&(amp|lt|gt|quot|apos|#x?[0-9a-fA-F]+);/g, (whole, code) => {
9827
9827
  switch (code) {
@@ -9863,7 +9863,7 @@ function visualWidth(text) {
9863
9863
  return w;
9864
9864
  }
9865
9865
 
9866
- // packages/core/dist/fs/pptx-tokenize.js
9866
+ // packages/core/dist/document/pptx-tokenize.js
9867
9867
  var RE = {
9868
9868
  slide: /^ppt\/slides\/slide(\d+)\.xml$/,
9869
9869
  sp: /<p:sp\b[^>]*>[\s\S]*?<\/p:sp>/g,
@@ -33251,7 +33251,7 @@ var require_xlsx = __commonJS({
33251
33251
  // apps/admin/data/skills.lib/document/bin-src/xlsx-query.mjs
33252
33252
  var import_promises = require("node:fs/promises");
33253
33253
 
33254
- // packages/core/dist/fs/xlsx-query.js
33254
+ // packages/core/dist/document/xlsx-query.js
33255
33255
  var XLSX = __toESM(require_xlsx(), 1);
33256
33256
  function parseWorkbook(buffer) {
33257
33257
  const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
@@ -81588,7 +81588,7 @@ var require_tiny_emitter = __commonJS({
81588
81588
  var import_promises = require("node:fs/promises");
81589
81589
  var import_node_path = require("node:path");
81590
81590
 
81591
- // packages/core/dist/fs/xlsx-recalc.js
81591
+ // packages/core/dist/document/xlsx-recalc.js
81592
81592
  var import_exceljs = __toESM(require_excel(), 1);
81593
81593
 
81594
81594
  // node_modules/hyperformula/es/parser/ColumnAddress.mjs
@@ -111706,7 +111706,7 @@ for (const pluginName of Object.getOwnPropertyNames(plugin_exports)) {
111706
111706
  }
111707
111707
  }
111708
111708
 
111709
- // packages/core/dist/fs/xlsx-recalc.js
111709
+ // packages/core/dist/document/xlsx-recalc.js
111710
111710
  function toPrimitive(v) {
111711
111711
  if (v == null)
111712
111712
  return { value: null };
@@ -0,0 +1,25 @@
1
+ {
2
+ "groups": [
3
+ { "id": "tech-future", "name_cn": "科技未来", "sample": "styles/_samples/_groups/tech-future.webp", "scenarios": ["科技", "发布会", "产品", "pitch"] },
4
+ { "id": "biz-premium", "name_cn": "商务高端", "sample": "styles/_samples/_groups/biz-premium.webp", "scenarios": ["金融", "年报", "路演", "招商", "董事会"] },
5
+ { "id": "minimal", "name_cn": "极简设计", "sample": "styles/_samples/_groups/minimal.webp", "scenarios": ["极简", "设计", "作品集"] },
6
+ { "id": "editorial", "name_cn": "编辑人文", "sample": "styles/_samples/_groups/editorial.webp", "scenarios": ["人文", "行业观察", "杂志感", "研究分享"] },
7
+ { "id": "creative", "name_cn": "创意手作", "sample": "styles/_samples/_groups/creative.webp", "scenarios": ["创意", "教学", "工作坊", "头脑风暴"] },
8
+ { "id": "natural", "name_cn": "自然温和", "sample": "styles/_samples/_groups/natural.webp", "scenarios": ["品牌手册", "可持续", "美妆", "零售"] }
9
+ ],
10
+ "entries": [
11
+ { "id": "cool", "kind": "skin", "group": "tech-future", "name_cn": "酷炫深色", "oneliner": "深蓝辉光 · 科技发布", "scenarios": ["科技", "发布", "pitch", "主题演讲"], "mode": "dark", "sample": "styles/_samples/cool.webp" },
12
+ { "id": "swiss-grid", "kind": "skin", "group": "tech-future", "name_cn": "瑞士国际", "oneliner": "克莱因蓝白 · 瑞士国际", "scenarios": ["科技产品", "数据汇报", "设计", "年度总结"], "mode": "light", "sample": "styles/_samples/swiss-grid.webp" },
13
+ { "id": "black-gold", "kind": "skin", "group": "biz-premium", "name_cn": "黑金", "oneliner": "纯黑金辉 · 高端商务", "scenarios": ["金融", "年报", "路演", "奢侈品"], "mode": "dark", "sample": "styles/_samples/black-gold.webp" },
14
+ { "id": "olive-gold", "kind": "skin", "group": "biz-premium", "name_cn": "橄榄金", "oneliner": "橄榄亮金 · 高端招商", "scenarios": ["高端", "证书", "招商", "品牌"], "mode": "dark", "sample": "styles/_samples/olive-gold.webp" },
15
+ { "id": "mckinsey", "kind": "skin", "group": "biz-premium", "name_cn": "白底咨询", "oneliner": "白底藏青 · 咨询评审", "scenarios": ["咨询", "战略汇报", "评审", "董事会"], "mode": "light", "sample": "styles/_samples/mckinsey.webp" },
16
+ { "id": "apple", "kind": "skin", "group": "minimal", "name_cn": "纯黑极简", "oneliner": "纯黑极简 · 产品发布", "scenarios": ["产品发布", "主题演讲", "极简演示"], "mode": "dark", "sample": "styles/_samples/apple.webp" },
17
+ { "id": "mono", "kind": "skin", "group": "minimal", "name_cn": "纯白黑灰", "oneliner": "纯白黑灰 · 极简设计", "scenarios": ["极简", "高端", "设计", "单色报告"], "mode": "light", "sample": "styles/_samples/mono.webp" },
18
+ { "id": "ivory-gold", "kind": "skin", "group": "minimal", "name_cn": "奶油青铜", "oneliner": "奶油青铜 · 奢华极简", "scenarios": ["奢华极简", "品牌手册", "路演", "高端零售"], "mode": "light", "sample": "styles/_samples/ivory-gold.webp" },
19
+ { "id": "magazine-ink", "kind": "skin", "group": "editorial", "name_cn": "杂志墨", "oneliner": "瓷白靛蓝 · 杂志人文", "scenarios": ["人文分享", "行业观察", "商业发布"], "mode": "light", "sample": "styles/_samples/magazine-ink.webp" },
20
+ { "id": "anthropic", "kind": "skin", "group": "editorial", "name_cn": "奶油珊瑚", "oneliner": "奶油珊瑚 · AI 研究", "scenarios": ["AI", "产品", "研究分享", "人文品牌"], "mode": "light", "sample": "styles/_samples/anthropic.webp" },
21
+ { "id": "hand-drawn", "kind": "skin", "group": "creative", "name_cn": "纸感手绘", "oneliner": "纸感手绘 · 创意教学", "scenarios": ["创意", "头脑风暴", "教学", "工作坊"], "mode": "light", "sample": "styles/_samples/hand-drawn.webp" },
22
+ { "id": "cinereel", "kind": "skin", "group": "creative", "name_cn": "黑白胶片", "oneliner": "黑白胶片 · 影视创意", "scenarios": ["影视", "创意作品集", "音乐", "传媒"], "mode": "dark", "sample": "styles/_samples/cinereel.webp" },
23
+ { "id": "branding", "kind": "skin", "group": "natural", "name_cn": "暖米绿意", "oneliner": "暖米绿意 · 品牌手册", "scenarios": ["品牌手册", "可持续", "美妆", "零售", "极简"], "mode": "light", "sample": "styles/_samples/branding.webp" }
24
+ ]
25
+ }
@@ -281,6 +281,197 @@ The shipped `layouts/*.tpl` are this recipe applied as structure-only slides —
281
281
  paste the nearest one and paint it with a skin (`--style`) rather than rebuilding
282
282
  the stack by hand; each already carries the 8 layers correctly wired.
283
283
 
284
+ **动画优先由族的 motion 预设派发**(`motion/<id>.json`,`catalog.json` 里该 entry 的
285
+ `motion` 字段指到它;`deck-build` 填槽时按每页 layout 的 role 自动注入
286
+ `data-anim*`/`data-transition*`)。手写 `data-anim`/`data-transition` 仍然优先 ——
287
+ `deck-build` 只在元素还没有该属性时才注入,用于特例覆盖派发结果。没有 motion 预设
288
+ 的族(当前 13 个 skin 在 P0 都没有)保持这一段以下描述的默认行为:不写
289
+ `data-anim` 就没有任何动画。
290
+
291
+ ## Motion — entrance animation + slide transitions
292
+
293
+ ### Entrance animation (`data-anim`) — opt-in, hero pages only
294
+
295
+ html2pptx emits **native PowerPoint entrance animations** (a real `<p:timing>`
296
+ build sequence — not a video, not a GIF). Mark an element with `data-anim` and it
297
+ becomes one build step; the deck then plays like a keynote instead of appearing
298
+ all at once.
299
+
300
+ **Off unless you ask for it.** No `data-anim` anywhere → no `<p:timing>` → byte-
301
+ identical output to before. Reach for it when the scenario is a **stage** —
302
+ 发布会 / 路演 / pitch / 主题演讲 — and skip it for 内审 / 报告 / 讲义 decks that
303
+ people read rather than watch.
304
+
305
+ #### The attribute contract
306
+
307
+ | attribute | value | default |
308
+ |---|---|---|
309
+ | `data-anim` | `fade` · `fade-up` · `float` · `appear` · `fly-up` · `fly-down` · `fly-left` · `fly-right` | — (required) |
310
+ | `data-anim-seq` | number — build order within the slide | `0`, then paint order |
311
+ | `data-anim-start` | `after` (chain) · `with` (simultaneous) · `onclick` | `after` |
312
+ | `data-anim-delay` | ms before this step | `0` first step, `200` after |
313
+ | `data-anim-dur` | ms the effect runs | `500` |
314
+
315
+ `fade-up` and `float` are the same gentle 5%-rise fade — the house default.
316
+ `fly-*` travels 30% of the slide and is loud; spend it once, on a cover. `appear`
317
+ is a hard cut with no fade (use for a punchline that should snap in).
318
+
319
+ Put the attribute on a **container** and the text inside inherits it — the walker
320
+ resolves each text run to its nearest `[data-anim]` ancestor, so one attribute on
321
+ a `.card` animates the whole card as a unit. That is almost always what you want:
322
+ animate BLOCKS, not individual words.
323
+
324
+ #### Playback model
325
+
326
+ The first step fires when the presenter advances to the slide's build; every later
327
+ step chains **after-previous**, so its `data-anim-delay` reads as the stagger
328
+ between items. One click plays the whole page — you never click per element.
329
+
330
+ #### Hard constraints (silent failure if ignored)
331
+
332
+ - **Only native shapes animate.** Anything baked into the raster backdrop is one
333
+ flat image and cannot be a step. That includes every `--talos-bake:1` title —
334
+ **`cinereel` and `ivory-gold` bake ALL their title classes**, so on those two
335
+ skins a `data-anim` on `.cover-title`/`.section-title` is silently dropped.
336
+ Animate the eyebrow, body, cards and image instead, or pick another skin.
337
+ **Same rule for a motion preset's `entrance.<role>[].sel`** — `deck-build` writes
338
+ `data-anim*` onto whatever the selector matches by class, so a preset step aimed
339
+ at a title class on a bake-everything skin drops just as silently; a family's
340
+ `motion/<id>.json` has to know its own skin's `--talos-bake` list.
341
+ - **`background-clip:text` is baked too** (layer 8 above) — same silent drop.
342
+ - **PDF flattens everything.** `doc-convert` / LibreOffice / Gotenberg ignore
343
+ `<p:timing>`; the animation exists only in the .pptx opened in PowerPoint,
344
+ Keynote or Impress. Never promise animation on a PDF deliverable.
345
+ - **Charts and images animate**, as whole objects — a `data-chart` cannot animate
346
+ series-by-series.
347
+
348
+ #### Recipes (paste onto the layout you already picked)
349
+
350
+ **Cover** — one statement, one beat:
351
+
352
+ ```html
353
+ <h1 class="cover-title" data-anim="fade-up" data-anim-seq="1" data-anim-dur="700">…</h1>
354
+ <div class="cover-sub" data-anim="fade-up" data-anim-seq="2" data-anim-delay="120">…</div>
355
+ ```
356
+
357
+ **Section divider** — the number lands, then the title:
358
+
359
+ ```html
360
+ <div class="section-ghost" data-anim="fade" data-anim-seq="1">03</div>
361
+ <h2 class="section-title" data-anim="fly-up" data-anim-seq="2" data-anim-delay="150">…</h2>
362
+ ```
363
+
364
+ **Card grid / TOC** — stagger the blocks, never the words. One attribute per card,
365
+ `seq` in reading order, a short even delay:
366
+
367
+ ```html
368
+ <div class="card" data-anim="fade-up" data-anim-seq="1">…</div>
369
+ <div class="card" data-anim="fade-up" data-anim-seq="2" data-anim-delay="140">…</div>
370
+ <div class="card" data-anim="fade-up" data-anim-seq="3" data-anim-delay="140">…</div>
371
+ ```
372
+
373
+ **Big stat** — the label sets up, the number pays off:
374
+
375
+ ```html
376
+ <div class="stat-lead" data-anim="fade" data-anim-seq="1">…</div>
377
+ <div class="stat-num" data-anim="appear" data-anim-seq="2" data-anim-delay="260">…</div>
378
+ ```
379
+
380
+ #### Discipline
381
+
382
+ - **≤4 steps per slide.** A build with eight steps is a slide with too much on it.
383
+ - **Hero pages only** — cover, section, big-stat, ending, and at most one content
384
+ page per chapter. A deck where *every* page builds is exhausting to present.
385
+ - **Never animate the chrome** (header/footer/page number/hairline) — the frame is
386
+ supposed to be constant; animating it makes the deck feel unstable.
387
+ - **Keep durations short** (500–700ms). Anything slower reads as lag on a projector.
388
+
389
+ ### Slide transitions (`data-transition`)
390
+
391
+ Where `data-anim` builds content WITHIN a slide, `data-transition` sets how the deck
392
+ moves BETWEEN slides. Put it on the `<section class="slide">` — it describes the move
393
+ **into** that slide.
394
+
395
+ | attribute | value | default |
396
+ |---|---|---|
397
+ | `data-transition` | `cut` · `fade` · `dissolve` · `wedge` · `wipe` · `push` · `cover` · `zoom` · `split` · `morph` · `none` | — (required) |
398
+ | `data-transition-dir` | `l` · `r` · `u` · `d` (wipe/push/cover) · `in` · `out` (zoom/split) | per-effect default |
399
+ | `data-transition-dur` | ms | the `med` speed bucket |
400
+
401
+ ```html
402
+ <section class="slide" data-transition="fade" data-transition-dur="600">…</section>
403
+ <section class="slide" data-transition="push" data-transition-dir="u">…</section>
404
+ ```
405
+
406
+ **`morph` is the one that makes a deck look produced** — PowerPoint tweens shapes that
407
+ persist across two slides instead of cutting. Two caveats before you reach for it:
408
+ it needs **PowerPoint 2016+** (older consumers get the fade fallback we emit), and in
409
+ hybrid mode most of each slide is a single baked backdrop image, so morph has little
410
+ to tween — it reads as a soft cross-dissolve unless the two slides share **native**
411
+ shapes (text/charts) in similar positions. Use it between slides that genuinely
412
+ continue one another (a title that moves, a stat that grows); elsewhere `fade` is more
413
+ honest and costs nothing.
414
+
415
+ **Pick one transition for the deck and stay with it** — a different effect per slide is
416
+ the single loudest "amateur deck" signal. `fade` for almost everything; `push` or
417
+ `cover` when chapters should feel like turning a page; `cut` (or nothing) for dense
418
+ analytical decks where motion is noise; `morph` for the two or three slides that
419
+ actually continue each other.
420
+
421
+ Same two constraints as animation: **PDF export flattens transitions** (they exist only
422
+ in the .pptx opened in PowerPoint/Keynote/Impress), and an unknown name degrades to
423
+ `fade` rather than failing.
424
+
425
+ ## Type & space scale — how a skin sets its own rhythm
426
+
427
+ Every `font-size` and page gutter in `layouts/*.tpl` is written as a scalable value:
428
+
429
+ ```html
430
+ font-size:calc(23px * var(--type-scale,1)) left:calc(96px * var(--space-scale,1))
431
+ ```
432
+
433
+ A skin sets `--space-scale` / `--type-scale` in its `:root` and the whole deck retimes —
434
+ **without touching a single layout**, and keeping each layout's internal hierarchy intact
435
+ (everything scales together). Both default to `1`, so a skin that ignores them renders
436
+ exactly as before. The shipped range runs from `mckinsey` at `0.86` (board-pack density)
437
+ to `apple` at `1.22` (keynote-stage air).
438
+
439
+ Two rules:
440
+
441
+ - **Hand-authoring a bespoke slide?** Write your sizes the same way
442
+ (`calc(48px * var(--type-scale,1))`) or that one slide will ignore the skin's rhythm
443
+ and sit at a different density than the rest of the deck.
444
+ - **Changed a scale? Re-run `deck-qa`.** Scaling reflows text; push it too far and content
445
+ runs off-canvas or collides. That is a mechanical check — never eyeball it.
446
+
447
+ ## Fonts — bundled faces reach the render, not the native text layer
448
+
449
+ `assets/fonts/fonts.json` is the single source of truth for the skill's font set.
450
+ `html2pptx` base64-injects every face from it at render; `scripts/deck-skin-samples.mjs`
451
+ and `scripts/deck-fidelity.mjs` serve the same files from disk. **Add a face there and
452
+ drop the `.woff2` beside it — never inline a base64 `@font-face` into a `skin.css`.**
453
+
454
+ The part that trips people up: an injected `@font-face` styles the **browser** render —
455
+ the raster backdrop, any `--talos-bake:1` text, `--rasterize` output, and the skin
456
+ preview cards. It does **not** reach the **native pptx text layer**. There a run carries
457
+ only a typeface *name*, and PowerPoint / Keynote / LibreOffice substitute whatever they
458
+ have installed. So a skin can name a face, we can bundle it, and the audience still sees
459
+ a substitute.
460
+
461
+ Three ways a non-system face actually survives into the delivered deck:
462
+
463
+ 1. **Bake it** (`--talos-bake:1` on the class) — what `cinereel` and `ivory-gold` do for
464
+ their Anton titles. Guaranteed correct; the text becomes part of the backdrop image,
465
+ so it is no longer editable, searchable, `deck-qa`-checkable, or animatable.
466
+ 2. **Embed it** — `bin/pptx-embed-fonts.cjs` writes an OOXML font embed. Needs a TTF
467
+ (we bundle woff2), and is only sane for small Latin faces, never CJK.
468
+ 3. **Ask for a system face** — Helvetica Neue / Georgia / Arial and the CJK families are
469
+ everywhere; that is why most skins lead with them.
470
+
471
+ A face that is bundled but neither baked nor embedded is *still worth bundling* (the
472
+ backdrop and the picker previews come out right), just don't assume the native text
473
+ followed. `hand-drawn`'s Gochi Hand heading is exactly that case today.
474
+
284
475
  ## Running a script (PptxGenJS via doc-run — NOT for decks)
285
476
 
286
477
  > **This section is reference for NON-deck freeform PptxGenJS only** (bespoke
@@ -108,6 +108,7 @@ Each slide carries `data-layout="<id>"` (drives the diversity lint + traceabilit
108
108
  | `map-quad` | content · data | dot-matrix world map + 4 FIXED corner % callouts | medium (4) | diagram (map) | 全球分布(四角固定;条目数可变用 `map-distribution`) |
109
109
  | `toc-agenda` | toc | single-column agenda | 5–7 items | text-only | 议程(单列,vs 双列 `toc`) |
110
110
  | `toc-panel` | toc | left title + dark side panel (rows) | 3–5 entries | text-only | 目录(左标题+右深色面板) |
111
+ | `toc-editorial` | toc | 2×2 numbered briefs + oversized side title | 4 chapters | text-only | 目录(杂志/影视感,右侧巨型标题) |
111
112
  | `stats-chart` | content · data | title + paragraph + panel bar chart | dense | diagram (bar) | 统计页(深色面板横向条形图) |
112
113
  | `blocks-2x2` | content | 2x2 blocks grid | medium (4) | text-only | 2×2 区块网格 |
113
114
  | `editorial-panel` | content | editorial panel layout | medium | text-only | 编辑面板版式 |
@@ -155,3 +156,34 @@ deck.html 时逐页决定要不要加这个类,skin 只需在自己的 `--slide-
155
156
  Adding a **skin** = one `styles/<name>/skin.css` defining the above; all layouts get
156
157
  it. Adding a **layout** = one `layouts/<id>.tpl` (structure-only, tagged here); all
157
158
  skins render it.
159
+
160
+ ## 反向通道 —— 包内版式如何进入共享库
161
+
162
+ 一个 `packs/<id>/` 可以带自己的专属版式(`packs/<id>/layouts/<id>.tpl`,与共享同名
163
+ 即遮蔽)。当包里做出来的某一页被证明**不是**包专属的装饰、而是别的族/包也会用得上
164
+ 的结构时,把它提升进这个共享库,而不是让每个包各自重复发明。
165
+
166
+ **准入判据**(spec §7.3):**剥掉所有颜色与 `font-family` 之后,它仍表达一个共享库
167
+ 没有的结构。** 是 → 提升;否(结构其实通用,专属感全靠色彩/字体/图形语汇撑)→ 留在
168
+ 包内,不要提升。
169
+
170
+ 跑 `node scripts/ppt-tpl/promote-layout.mjs <packId> <layoutId>`。它只机械校验"可
171
+ 提升"的必要条件(零硬编码色、不带私有 `font-family`、只用契约内 class、规范的
172
+ 1280×720 单 `section` + `data-layout`、至少一个可填槽位、`layouts/README.md` 表头
173
+ 格式没变)——**是不是结构性创新仍需人来判**,脚本不代劳。任一条不满足就拒绝写入
174
+ (不移动文件),并逐条报出缺什么。
175
+
176
+ 校验通过后脚本会:把 `.tpl` 移到 `layouts/`、重跑 `scripts/gen-slots.mjs` 重生成
177
+ `slots.json`、在本文件的 Catalog 表格里插入一行占位(`role`/`structure`/`density`/
178
+ `has-image`/`pick when` 均为 `TODO`,附 `promoted from packs/<packId>`)。写入中途
179
+ 任何一步失败都会整体回滚(删掉刚写的 `.tpl`,`slots.json`/本文件复原),不会留下
180
+ 半成品。
181
+
182
+ 提升不是终点,脚本打印的四步收尾都要做:补全本文件里那一行的全部 `TODO`、从
183
+ `packs/<packId>/layouts/` 删掉原文件(否则同名遮蔽会让包永远看不到共享版本、也
184
+ 永远吃不到后续对共享版式的修复)、`node scripts/deck-skin-samples.mjs && node
185
+ scripts/deck-fidelity.mjs` 确认它在所有皮肤下都成立、再跑
186
+ `TALOS_TEST_SCOPE=unit npx vitest run tests/unit/deck-layouts.test.ts`。
187
+
188
+ 新版式若用到契约外的 class,先扩 `styles/_contract-defaults.css`(本脚本不代劳)——
189
+ 但只有 **≥3 个族/包各自独立地需要同一个新原语**时才扩,避免契约被单个包的口味撑肥。
@@ -1,22 +1,22 @@
1
1
  <!-- layouts/banner-columns — structure-only (paint via skin). 通栏 banner 大写标题 + 下方 3 栏项目符号文本(使用说明/须知/多方案并列). 深色皮肤(black-gold/cool)下呈"浅带+描金标题+浅字"参考观感;浅色皮肤下呈"实色带+白标题". data-layout drives P1/P2/P3 + dedup. -->
2
2
  <section class="slide" data-layout="banner-columns" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div>
3
3
  <!-- ===== TOP BANNER ===== -->
4
- <div class="banner" style="position:absolute;left:0;right:0;top:32px;height:150px;display:flex;align-items:center;justify-content:center;padding:0 56px"><div class="banner-title" style="font-size:58px;font-weight:800;letter-spacing:.01em;text-transform:uppercase;line-height:1;text-align:center">{{banner|How to use this presentation}}</div></div>
4
+ <div class="banner" style="position:absolute;left:0;right:0;top:32px;height:150px;display:flex;align-items:center;justify-content:center;padding:0 56px"><div class="banner-title" style="font-size:calc(58px * var(--type-scale,1));font-weight:800;letter-spacing:.01em;text-transform:uppercase;line-height:1;text-align:center">{{banner|How to use this presentation}}</div></div>
5
5
  <!-- ===== 3 COLUMNS ===== -->
6
6
  <div style="position:absolute;left:56px;right:56px;top:250px;bottom:44px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:44px">
7
7
  <div class="col">
8
- <div class="col-title" style="text-align:center;font-size:24px;font-weight:700;margin-bottom:28px">{{col1_title|分栏标题一}}</div>
9
- <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:15px;line-height:1.7;text-align:justify">{{b1|一段说明文字,两三行,替换为真实内容。可以写操作步骤或注意事项。}}</p></div>
10
- <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:15px;line-height:1.7;text-align:justify">{{b2|<span style="text-decoration:underline">备选:</span> 第二条说明,延展一句,替换为真实内容,收束到要点。}}</p></div>
8
+ <div class="col-title" style="text-align:center;font-size:calc(24px * var(--type-scale,1));font-weight:700;margin-bottom:28px">{{col1_title|分栏标题一}}</div>
9
+ <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;text-align:justify">{{b1|一段说明文字,两三行,替换为真实内容。可以写操作步骤或注意事项。}}</p></div>
10
+ <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;text-align:justify">{{b2|<span style="text-decoration:underline">备选:</span> 第二条说明,延展一句,替换为真实内容,收束到要点。}}</p></div>
11
11
  </div>
12
12
  <div class="col">
13
- <div class="col-title" style="text-align:center;font-size:24px;font-weight:700;margin-bottom:28px">{{col2_title|分栏标题二}}</div>
14
- <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:15px;line-height:1.7;text-align:justify">{{b3|一段说明文字,两三行,替换为真实内容。}}</p></div>
15
- <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:15px;line-height:1.7;text-align:justify">{{b4|<span style="text-decoration:underline">备选:</span> 第二条说明,延展一句,替换为真实内容。}}</p></div>
13
+ <div class="col-title" style="text-align:center;font-size:calc(24px * var(--type-scale,1));font-weight:700;margin-bottom:28px">{{col2_title|分栏标题二}}</div>
14
+ <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;text-align:justify">{{b3|一段说明文字,两三行,替换为真实内容。}}</p></div>
15
+ <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;text-align:justify">{{b4|<span style="text-decoration:underline">备选:</span> 第二条说明,延展一句,替换为真实内容。}}</p></div>
16
16
  </div>
17
17
  <div class="col">
18
- <div class="col-title" style="text-align:center;font-size:24px;font-weight:700;margin-bottom:28px">{{col3_title|分栏标题三}}</div>
19
- <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:15px;line-height:1.7;text-align:justify">{{b5|一段说明文字,两三行,替换为真实内容。}}</p></div>
18
+ <div class="col-title" style="text-align:center;font-size:calc(24px * var(--type-scale,1));font-weight:700;margin-bottom:28px">{{col3_title|分栏标题三}}</div>
19
+ <div class="col-item" style="display:flex;gap:11px;margin-bottom:20px"><span class="col-bullet" style="width:5px;height:5px;border-radius:50%;flex:none;margin-top:9px;display:inline-block"></span><p class="col-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;text-align:justify">{{b5|一段说明文字,两三行,替换为真实内容。}}</p></div>
20
20
  </div>
21
21
  </div>
22
22
  </section>
@@ -1,4 +1,4 @@
1
1
  <!-- layouts/bento — structure-only variant (paint via skin). -->
2
- <section class="slide" data-layout="bento" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:96px;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:13px;letter-spacing:.28em">{{eyebrow|AT A GLANCE}}</span></div><h2 class="deck-title" style="position:absolute;left:92px;top:158px;font-size:48px;letter-spacing:-.4px">{{title|总览}}</h2>
3
- <div class="card-grid" style="position:absolute;left:96px;right:96px;top:270px;bottom:70px;display:grid;grid-template-columns:1.6fr 1fr 1fr;grid-template-rows:1fr 1fr;gap:18px"><div class="card" style="grid-row:1 / span 2;position:relative;padding:34px;display:flex;flex-direction:column;justify-content:space-between"><span class="card-rail" style="position:absolute;left:0;top:34px;width:3px;height:44px;border-radius:2px"></span><div class="card-title" style="font-size:23px;font-weight:700">{{big_title|核心指标}}</div><div><div class="kpi-num" style="font-size:88px;font-weight:800;line-height:1">{{big_num|38}}<span class="stat-unit" style="font-size:34px">{{big_unit|B}}</span></div><p class="card-body" style="font-size:15px;margin-top:10px">{{big_body|一句说明,替换为真实内容。}}</p></div></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:19px;font-weight:700">{{card1_title|要点 01}}</div><p class="card-body" style="font-size:14px;line-height:1.55;margin-top:8px">{{card1_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:19px;font-weight:700">{{card2_title|要点 02}}</div><p class="card-body" style="font-size:14px;line-height:1.55;margin-top:8px">{{card2_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:19px;font-weight:700">{{card3_title|要点 03}}</div><p class="card-body" style="font-size:14px;line-height:1.55;margin-top:8px">{{card3_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:19px;font-weight:700">{{card4_title|要点 04}}</div><p class="card-body" style="font-size:14px;line-height:1.55;margin-top:8px">{{card4_body|一句说明。}}</p></div></div>
4
- <div class="rule rule-foot" style="position:absolute;left:96px;right:96px;bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:96px;bottom:17px;font-size:12px;letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:96px;bottom:17px;font-size:12px">{{pageno|01}}</div></section>
2
+ <section class="slide" data-layout="bento" 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|AT A GLANCE}}</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:270px;bottom:70px;display:grid;grid-template-columns:1.6fr 1fr 1fr;grid-template-rows:1fr 1fr;gap:18px"><div class="card" style="grid-row:1 / span 2;position:relative;padding:34px;display:flex;flex-direction:column;justify-content:space-between"><span class="card-rail" style="position:absolute;left:0;top:34px;width:3px;height:44px;border-radius:2px"></span><div class="card-title" style="font-size:calc(23px * var(--type-scale,1));font-weight:700">{{big_title|核心指标}}</div><div><div class="kpi-num" style="font-size:calc(88px * var(--type-scale,1));font-weight:800;line-height:1">{{big_num|38}}<span class="stat-unit" style="font-size:calc(34px * var(--type-scale,1))">{{big_unit|B}}</span></div><p class="card-body" style="font-size:calc(15px * var(--type-scale,1));margin-top:10px">{{big_body|一句说明,替换为真实内容。}}</p></div></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:calc(19px * var(--type-scale,1));font-weight:700">{{card1_title|要点 01}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.55;margin-top:8px">{{card1_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:calc(19px * var(--type-scale,1));font-weight:700">{{card2_title|要点 02}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.55;margin-top:8px">{{card2_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:calc(19px * var(--type-scale,1));font-weight:700">{{card3_title|要点 03}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.55;margin-top:8px">{{card3_body|一句说明。}}</p></div><div class="card" style="position:relative;padding:26px"><span class="card-rail" style="position:absolute;left:0;top:26px;width:3px;height:34px;border-radius:2px"></span><div class="card-title" style="font-size:calc(19px * var(--type-scale,1));font-weight:700">{{card4_title|要点 04}}</div><p class="card-body" style="font-size:calc(14px * var(--type-scale,1));line-height:1.55;margin-top:8px">{{card4_body|一句说明。}}</p></div></div>
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/big-stat — structure-only (paint via styles/<skin>/skin.css). data-layout drives P1/P2/P3 + dedup. -->
2
- <section class="slide" data-layout="big-stat" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:96px;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:13px;letter-spacing:.28em">{{eyebrow|KEY METRIC}}</span></div><h2 class="deck-title" style="position:absolute;left:92px;top:158px;font-size:48px;letter-spacing:-.4px">{{title|}}</h2>
3
- <div class="stat-num" style="position:absolute;left:90px;top:196px;font-weight:800;line-height:1;font-size:216px;letter-spacing:-2px">{{stat|585}}<span class="stat-unit" style="font-size:64px">{{unit| 单位}}</span></div><div class="stat-lead" style="position:absolute;left:100px;top:492px;font-size:30px;font-weight:600">{{lead|一句结论,数字说明了什么}}</div><p class="stat-note" style="position:absolute;left:100px;top:556px;width:900px;font-size:17px;line-height:1.6">{{note|一句支撑说明,给上下文与来源。}}</p>
4
- <div class="rule rule-foot" style="position:absolute;left:96px;right:96px;bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:96px;bottom:17px;font-size:12px;letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:96px;bottom:17px;font-size:12px">{{pageno|01}}</div></section>
2
+ <section class="slide" data-layout="big-stat" 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|KEY METRIC}}</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="stat-num" style="position:absolute;left:90px;top:196px;font-weight:800;line-height:1;font-size:calc(216px * var(--type-scale,1));letter-spacing:-2px">{{stat|585}}<span class="stat-unit" style="font-size:calc(64px * var(--type-scale,1))">{{unit| 单位}}</span></div><div class="stat-lead" style="position:absolute;left:100px;top:492px;font-size:calc(30px * var(--type-scale,1));font-weight:600">{{lead|一句结论,数字说明了什么}}</div><p class="stat-note" style="position:absolute;left:100px;top:556px;width:900px;font-size:calc(17px * var(--type-scale,1));line-height:1.6">{{note|一句支撑说明,给上下文与来源。}}</p>
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>
@@ -2,18 +2,18 @@
2
2
  <section class="slide" data-layout="blocks-2x2" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div>
3
3
 
4
4
 
5
- <div class="eyebrow-row" style="position:absolute;left:96px;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:13px;letter-spacing:.28em">{{eyebrow|PRINCIPLES}}</span></div>
6
- <h2 class="deck-title" style="position:absolute;left:92px;top:146px;font-size:42px;letter-spacing:-.4px">{{title|章节主标题}}</h2>
7
- <p class="card-body" style="position:absolute;left:96px;right:96px;top:214px;font-size:16px;line-height:1.7">{{intro|一段引子说明,两三行,交代这一章的核心观点与背景,替换为真实内容。承接标题,引出下面四个要点。}}</p>
8
- <div class="card-grid" style="position:absolute;left:96px;right:96px;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:34px;font-weight:800;line-height:1">01</span><div class="card-title" style="font-size:22px;font-weight:700;margin-top:6px">{{block1_title|要点一标题}}</div><p class="card-body" style="font-size:14px;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:34px;font-weight:800;line-height:1">02</span><div class="card-title" style="font-size:22px;font-weight:700;margin-top:6px">{{block2_title|要点二标题}}</div><p class="card-body" style="font-size:14px;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:34px;font-weight:800;line-height:1">03</span><div class="card-title" style="font-size:22px;font-weight:700;margin-top:6px">{{block3_title|要点三标题}}</div><p class="card-body" style="font-size:14px;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:34px;font-weight:800;line-height:1">04</span><div class="card-title" style="font-size:22px;font-weight:700;margin-top:6px">{{block4_title|要点四标题}}</div><p class="card-body" style="font-size:14px;line-height:1.5;margin-top:6px">{{block4_body|一句说明,替换为真实内容。}}</p></div>
5
+ <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
+ <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>
13
13
  </div>
14
- <div style="position:absolute;left:96px;right:96px;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:17px;font-weight:700">{{quote|"一句金句,点睛这一章。"}}</div><div class="quote-attr" style="font-size:13px;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:12px;font-weight:700">参考资料:</span><span class="footnote-body" style="font-size:12px"> {{refs|来源一;来源二}}</span></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
17
  </div>
18
- <div class="rule rule-foot" style="position:absolute;left:96px;right:96px;bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:96px;bottom:17px;font-size:12px;letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:96px;bottom:17px;font-size:12px">{{pageno|01}}</div>
18
+ <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
19
  </section>
@@ -1,9 +1,9 @@
1
1
  <!-- layouts/brand-values — structure-only (paint via skin). 品牌手册"品牌主张":每张卡 编号圆({{_nn}}) + 准则标题 + 说明. rows.values{name,body} — 3 张最佳,2–4 张自适应. 复用既有 class(.surface/.step-circle/.step-title/.step-body). data-layout drives P1/P2/P3 + dedup. -->
2
2
  <section class="slide" data-layout="brand-values" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div>
3
- <div class="eyebrow-row" style="position:absolute;left:96px;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:13px;letter-spacing:.28em">{{eyebrow|BRAND VALUES}}</span></div>
4
- <h2 class="deck-title" style="position:absolute;left:92px;top:158px;font-size:48px;letter-spacing:-.4px">{{title|品牌主张}}</h2>
5
- <div class="steps" style="position:absolute;left:96px;right:96px;top:280px;bottom:96px;display:flex;gap:28px">
6
- {{#values}}<div class="step surface" style="flex:1;padding:34px 32px;display:flex;flex-direction:column"><div class="step-circle" style="width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:26px;font-weight:700;line-height:1">{{_nn|01}}</div><div class="step-title" style="font-size:22px;font-weight:700;font-family:var(--font-head);margin-top:22px">{{name|占位准则 · Value}}</div><p class="step-body" style="font-size:15px;line-height:1.7;margin-top:10px">{{body|一句准则说明,表达品牌的核心态度,替换为真实内容。}}</p></div>{{/values}}
3
+ <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|BRAND VALUES}}</span></div>
4
+ <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>
5
+ <div class="steps" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));top:280px;bottom:96px;display:flex;gap:28px">
6
+ {{#values}}<div class="step surface" style="flex:1;padding:34px 32px;display:flex;flex-direction:column"><div class="step-circle" style="width:64px;height:64px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:calc(26px * var(--type-scale,1));font-weight:700;line-height:1">{{_nn|01}}</div><div class="step-title" style="font-size:calc(22px * var(--type-scale,1));font-weight:700;font-family:var(--font-head);margin-top:22px">{{name|占位准则 · Value}}</div><p class="step-body" style="font-size:calc(15px * var(--type-scale,1));line-height:1.7;margin-top:10px">{{body|一句准则说明,表达品牌的核心态度,替换为真实内容。}}</p></div>{{/values}}
7
7
  </div>
8
- <div class="rule rule-foot" style="position:absolute;left:96px;right:96px;bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:96px;bottom:17px;font-size:12px;letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:96px;bottom:17px;font-size:12px">{{pageno|01}}</div>
8
+ <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>
9
9
  </section>