scrum-skills 0.3.2 → 0.3.4

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 (365) hide show
  1. package/.agents/skills/diagram-design/LICENSE +4 -0
  2. package/.agents/skills/diagram-design/SKILL.md +423 -0
  3. package/.agents/skills/diagram-design/UPSTREAM.json +88 -0
  4. package/.agents/skills/diagram-design/UPSTREAM.md +23 -0
  5. package/.agents/skills/diagram-design/assets/example-architecture-containment.html +205 -0
  6. package/.agents/skills/diagram-design/assets/example-architecture-delta.html +193 -0
  7. package/.agents/skills/diagram-design/assets/example-architecture.html +183 -0
  8. package/.agents/skills/diagram-design/assets/example-axonometric-plan-campus.html +108 -0
  9. package/.agents/skills/diagram-design/assets/example-axonometric-plan-coffee-shop.html +121 -0
  10. package/.agents/skills/diagram-design/assets/example-axonometric-plan-warehouse.html +127 -0
  11. package/.agents/skills/diagram-design/assets/example-axonometric-plan.html +114 -0
  12. package/.agents/skills/diagram-design/assets/example-bar.html +129 -0
  13. package/.agents/skills/diagram-design/assets/example-beeswarm.html +384 -0
  14. package/.agents/skills/diagram-design/assets/example-box-plot.html +127 -0
  15. package/.agents/skills/diagram-design/assets/example-bubble.html +147 -0
  16. package/.agents/skills/diagram-design/assets/example-bump.html +142 -0
  17. package/.agents/skills/diagram-design/assets/example-data-flow.html +143 -0
  18. package/.agents/skills/diagram-design/assets/example-datalake.html +269 -0
  19. package/.agents/skills/diagram-design/assets/example-db-schema.html +302 -0
  20. package/.agents/skills/diagram-design/assets/example-dependency.html +224 -0
  21. package/.agents/skills/diagram-design/assets/example-deployment.html +190 -0
  22. package/.agents/skills/diagram-design/assets/example-dp-integration.html +81 -0
  23. package/.agents/skills/diagram-design/assets/example-dp-security-matrix.html +88 -0
  24. package/.agents/skills/diagram-design/assets/example-er.html +202 -0
  25. package/.agents/skills/diagram-design/assets/example-exploded-ai-stack.html +85 -0
  26. package/.agents/skills/diagram-design/assets/example-exploded-keyboard.html +84 -0
  27. package/.agents/skills/diagram-design/assets/example-exploded-phone.html +83 -0
  28. package/.agents/skills/diagram-design/assets/example-exploded-unboxing.html +84 -0
  29. package/.agents/skills/diagram-design/assets/example-exploded.html +83 -0
  30. package/.agents/skills/diagram-design/assets/example-fishbone.html +152 -0
  31. package/.agents/skills/diagram-design/assets/example-flowchart.html +163 -0
  32. package/.agents/skills/diagram-design/assets/example-gantt.html +137 -0
  33. package/.agents/skills/diagram-design/assets/example-heatmap.html +224 -0
  34. package/.agents/skills/diagram-design/assets/example-high-level-vertical.html +325 -0
  35. package/.agents/skills/diagram-design/assets/example-high-level.html +301 -0
  36. package/.agents/skills/diagram-design/assets/example-import-drawio.html +185 -0
  37. package/.agents/skills/diagram-design/assets/example-import-excalidraw.html +70 -0
  38. package/.agents/skills/diagram-design/assets/example-import-mermaid.html +70 -0
  39. package/.agents/skills/diagram-design/assets/example-it-state.html +128 -0
  40. package/.agents/skills/diagram-design/assets/example-journey.html +148 -0
  41. package/.agents/skills/diagram-design/assets/example-kanban.html +174 -0
  42. package/.agents/skills/diagram-design/assets/example-layers.html +123 -0
  43. package/.agents/skills/diagram-design/assets/example-line.html +111 -0
  44. package/.agents/skills/diagram-design/assets/example-loop.html +100 -0
  45. package/.agents/skills/diagram-design/assets/example-marimekko.html +148 -0
  46. package/.agents/skills/diagram-design/assets/example-medallion.html +159 -0
  47. package/.agents/skills/diagram-design/assets/example-nested.html +136 -0
  48. package/.agents/skills/diagram-design/assets/example-org-chart.html +45 -0
  49. package/.agents/skills/diagram-design/assets/example-polar.html +116 -0
  50. package/.agents/skills/diagram-design/assets/example-process.html +64 -0
  51. package/.agents/skills/diagram-design/assets/example-pyramid.html +119 -0
  52. package/.agents/skills/diagram-design/assets/example-quadrant-consultant.html +166 -0
  53. package/.agents/skills/diagram-design/assets/example-quadrant.html +135 -0
  54. package/.agents/skills/diagram-design/assets/example-radar.html +139 -0
  55. package/.agents/skills/diagram-design/assets/example-ridgeline.html +104 -0
  56. package/.agents/skills/diagram-design/assets/example-sankey.html +150 -0
  57. package/.agents/skills/diagram-design/assets/example-scatter.html +141 -0
  58. package/.agents/skills/diagram-design/assets/example-sequence-oauth.html +227 -0
  59. package/.agents/skills/diagram-design/assets/example-sequence.html +222 -0
  60. package/.agents/skills/diagram-design/assets/example-service-blueprint.html +185 -0
  61. package/.agents/skills/diagram-design/assets/example-slopegraph.html +119 -0
  62. package/.agents/skills/diagram-design/assets/example-state-lifecycle.html +92 -0
  63. package/.agents/skills/diagram-design/assets/example-state.html +147 -0
  64. package/.agents/skills/diagram-design/assets/example-story-map.html +184 -0
  65. package/.agents/skills/diagram-design/assets/example-streamgraph.html +99 -0
  66. package/.agents/skills/diagram-design/assets/example-swimlane.html +172 -0
  67. package/.agents/skills/diagram-design/assets/example-timeline.html +135 -0
  68. package/.agents/skills/diagram-design/assets/example-tree-block-decomposition.html +151 -0
  69. package/.agents/skills/diagram-design/assets/example-tree.html +173 -0
  70. package/.agents/skills/diagram-design/assets/example-treemap.html +107 -0
  71. package/.agents/skills/diagram-design/assets/example-uml-class.html +188 -0
  72. package/.agents/skills/diagram-design/assets/example-venn.html +110 -0
  73. package/.agents/skills/diagram-design/assets/example-wardley.html +153 -0
  74. package/.agents/skills/diagram-design/assets/example-waterfall.html +129 -0
  75. package/.agents/skills/diagram-design/assets/template-dark.html +99 -0
  76. package/.agents/skills/diagram-design/assets/template-full.html +421 -0
  77. package/.agents/skills/diagram-design/assets/template-motion.html +448 -0
  78. package/.agents/skills/diagram-design/assets/template-terminal.html +188 -0
  79. package/.agents/skills/diagram-design/assets/template.html +100 -0
  80. package/.agents/skills/diagram-design/references/animation.md +143 -0
  81. package/.agents/skills/diagram-design/references/export-registry.md +78 -0
  82. package/.agents/skills/diagram-design/references/export.md +376 -0
  83. package/.agents/skills/diagram-design/references/import-drawio.md +181 -0
  84. package/.agents/skills/diagram-design/references/import-excalidraw.md +130 -0
  85. package/.agents/skills/diagram-design/references/import-mermaid.md +137 -0
  86. package/.agents/skills/diagram-design/references/layout-budget.md +97 -0
  87. package/.agents/skills/diagram-design/references/onboarding.md +368 -0
  88. package/.agents/skills/diagram-design/references/output-spec.md +277 -0
  89. package/.agents/skills/diagram-design/references/primitive-annotation.md +36 -0
  90. package/.agents/skills/diagram-design/references/primitive-icons.md +827 -0
  91. package/.agents/skills/diagram-design/references/primitive-sketchy.md +43 -0
  92. package/.agents/skills/diagram-design/references/primitive-terminal.md +76 -0
  93. package/.agents/skills/diagram-design/references/primitives-core.md +150 -0
  94. package/.agents/skills/diagram-design/references/profiles.md +183 -0
  95. package/.agents/skills/diagram-design/references/semantic-patterns.md +154 -0
  96. package/.agents/skills/diagram-design/references/style-guide.md +236 -0
  97. package/.agents/skills/diagram-design/references/style-vivid.md +148 -0
  98. package/.agents/skills/diagram-design/references/type-architecture-delta.md +143 -0
  99. package/.agents/skills/diagram-design/references/type-architecture.md +117 -0
  100. package/.agents/skills/diagram-design/references/type-axonometric-plan.md +83 -0
  101. package/.agents/skills/diagram-design/references/type-bar.md +108 -0
  102. package/.agents/skills/diagram-design/references/type-data-flow.md +371 -0
  103. package/.agents/skills/diagram-design/references/type-db-schema.md +48 -0
  104. package/.agents/skills/diagram-design/references/type-dependency.md +44 -0
  105. package/.agents/skills/diagram-design/references/type-deployment.md +45 -0
  106. package/.agents/skills/diagram-design/references/type-dp-integration.md +407 -0
  107. package/.agents/skills/diagram-design/references/type-dp-security-matrix.md +379 -0
  108. package/.agents/skills/diagram-design/references/type-er.md +25 -0
  109. package/.agents/skills/diagram-design/references/type-exploded.md +115 -0
  110. package/.agents/skills/diagram-design/references/type-fishbone.md +75 -0
  111. package/.agents/skills/diagram-design/references/type-flowchart.md +23 -0
  112. package/.agents/skills/diagram-design/references/type-gantt.md +45 -0
  113. package/.agents/skills/diagram-design/references/type-heatmap.md +80 -0
  114. package/.agents/skills/diagram-design/references/type-high-level.md +470 -0
  115. package/.agents/skills/diagram-design/references/type-it-state.md +468 -0
  116. package/.agents/skills/diagram-design/references/type-journey.md +55 -0
  117. package/.agents/skills/diagram-design/references/type-kanban.md +49 -0
  118. package/.agents/skills/diagram-design/references/type-layers.md +26 -0
  119. package/.agents/skills/diagram-design/references/type-line.md +337 -0
  120. package/.agents/skills/diagram-design/references/type-loop.md +223 -0
  121. package/.agents/skills/diagram-design/references/type-medallion.md +356 -0
  122. package/.agents/skills/diagram-design/references/type-nested.md +22 -0
  123. package/.agents/skills/diagram-design/references/type-org-chart.md +44 -0
  124. package/.agents/skills/diagram-design/references/type-polar.md +136 -0
  125. package/.agents/skills/diagram-design/references/type-process.md +490 -0
  126. package/.agents/skills/diagram-design/references/type-pyramid.md +33 -0
  127. package/.agents/skills/diagram-design/references/type-quadrant.md +81 -0
  128. package/.agents/skills/diagram-design/references/type-radar.md +82 -0
  129. package/.agents/skills/diagram-design/references/type-sankey.md +75 -0
  130. package/.agents/skills/diagram-design/references/type-scatter.md +276 -0
  131. package/.agents/skills/diagram-design/references/type-sequence.md +130 -0
  132. package/.agents/skills/diagram-design/references/type-service-blueprint.md +103 -0
  133. package/.agents/skills/diagram-design/references/type-state.md +30 -0
  134. package/.agents/skills/diagram-design/references/type-story-map.md +46 -0
  135. package/.agents/skills/diagram-design/references/type-swimlane.md +22 -0
  136. package/.agents/skills/diagram-design/references/type-timeline.md +20 -0
  137. package/.agents/skills/diagram-design/references/type-tree.md +24 -0
  138. package/.agents/skills/diagram-design/references/type-treemap.md +137 -0
  139. package/.agents/skills/diagram-design/references/type-uml-class.md +65 -0
  140. package/.agents/skills/diagram-design/references/type-venn.md +26 -0
  141. package/.agents/skills/diagram-design/references/type-wardley.md +39 -0
  142. package/.agents/skills/diagram-design/references/type-waterfall.md +75 -0
  143. package/.agents/skills/scrum-meta/SKILL.md +36 -36
  144. package/.agents/skills/scrum-planning/SKILL.md +61 -61
  145. package/.agents/skills/scrum-planning/references/schema.md +384 -336
  146. package/.agents/skills/scrum-report/SKILL.md +42 -42
  147. package/.agents/skills/scrum-sprint/SKILL.md +49 -49
  148. package/.agents/skills/scrum-tdd/SKILL.md +140 -127
  149. package/README.md +24 -1
  150. package/assets/board/200.html +1 -1
  151. package/assets/board/404.html +1 -1
  152. package/assets/board/_nuxt/4gQF_HS3.js +1 -0
  153. package/assets/board/_nuxt/5okfNy5D.js +1 -0
  154. package/assets/board/_nuxt/{Bb3Limos.js → B0C2jsdk.js} +1 -1
  155. package/assets/board/_nuxt/B1j6UC4U.js +1 -0
  156. package/assets/board/_nuxt/B3LKy6o2.js +1 -0
  157. package/assets/board/_nuxt/BAQQngAq.js +13 -0
  158. package/assets/board/_nuxt/BE6t7Q2m.js +1 -0
  159. package/assets/board/_nuxt/BGwhkDRl.js +1 -0
  160. package/assets/board/_nuxt/BLvbupFS.js +1 -0
  161. package/assets/board/_nuxt/BQgzP7ur.js +1 -0
  162. package/assets/board/_nuxt/BRZIF_wo.js +1 -0
  163. package/assets/board/_nuxt/BU8vdZUs.js +95 -0
  164. package/assets/board/_nuxt/BW3xJdEx.js +1 -0
  165. package/assets/board/_nuxt/{Cm9lkUvP.js → BY36DFyj.js} +1 -1
  166. package/assets/board/_nuxt/BZlZD94i.js +1 -0
  167. package/assets/board/_nuxt/BZvXNwev.js +3 -0
  168. package/assets/board/_nuxt/BiWrMOsL.js +1 -0
  169. package/assets/board/_nuxt/BkoKCNUY.js +1 -0
  170. package/assets/board/_nuxt/BlKmZhhF.js +1 -0
  171. package/assets/board/_nuxt/BmBpmU73.js +1 -0
  172. package/assets/board/_nuxt/BmrSh0rL.js +1 -0
  173. package/assets/board/_nuxt/BrWE0up6.js +1 -0
  174. package/assets/board/_nuxt/Bs52qkgk.js +1 -0
  175. package/assets/board/_nuxt/BuBzMkFZ.js +1 -0
  176. package/assets/board/_nuxt/Bubk0xn-.js +1 -0
  177. package/assets/board/_nuxt/BxuBMtk_.js +3 -0
  178. package/assets/board/_nuxt/By1KXXLR.js +1 -0
  179. package/assets/board/_nuxt/BygIGL69.js +2 -0
  180. package/assets/board/_nuxt/C-fx-vFO.js +1 -0
  181. package/assets/board/_nuxt/C1iO5KH3.js +1 -0
  182. package/assets/board/_nuxt/C2YPmTzt.js +1 -0
  183. package/assets/board/_nuxt/C3SpAhCW.js +1 -0
  184. package/assets/board/_nuxt/C3ZRWz5L.js +1 -0
  185. package/assets/board/_nuxt/C4WdPP6K.js +1 -0
  186. package/assets/board/_nuxt/C6o03JHe.js +1 -0
  187. package/assets/board/_nuxt/C8qB5llI.js +1 -0
  188. package/assets/board/_nuxt/C9MgRdhu.js +1 -0
  189. package/assets/board/_nuxt/CCA81-4P.js +1 -0
  190. package/assets/board/_nuxt/{D2O8Q8x9.js → CFCM18fF.js} +1 -1
  191. package/assets/board/_nuxt/CGXljzd_.js +1 -0
  192. package/assets/board/_nuxt/CI0scS-N.js +1 -0
  193. package/assets/board/_nuxt/CJs9B42o.js +1 -0
  194. package/assets/board/_nuxt/COmtTtfB.js +1 -0
  195. package/assets/board/_nuxt/CPYm4J_K.js +1 -0
  196. package/assets/board/_nuxt/CXG7GZes.js +1 -0
  197. package/assets/board/_nuxt/CYGiZn-X.js +1 -0
  198. package/assets/board/_nuxt/CaE8VlUp.js +1 -0
  199. package/assets/board/_nuxt/Cajxc4Dw.js +1 -0
  200. package/assets/board/_nuxt/CcGiNUgA.js +1 -0
  201. package/assets/board/_nuxt/Ccgv3lDj.js +1 -0
  202. package/assets/board/_nuxt/CdPGFZyy.js +1 -0
  203. package/assets/board/_nuxt/{DfR3IZN_.js → Cdf_T8Xa.js} +1 -1
  204. package/assets/board/_nuxt/CgQ30j_6.js +1 -0
  205. package/assets/board/_nuxt/Ck0-FqVI.js +1 -0
  206. package/assets/board/_nuxt/CkWKLtjO.js +1 -0
  207. package/assets/board/_nuxt/CoipdpDu.js +1 -0
  208. package/assets/board/_nuxt/Cq7hsCKB.js +1 -0
  209. package/assets/board/_nuxt/D166WVUG.js +1 -0
  210. package/assets/board/_nuxt/D1V1gysQ.js +1 -0
  211. package/assets/board/_nuxt/D4Dpzo9e.js +1 -0
  212. package/assets/board/_nuxt/D5i92OZO.js +1 -0
  213. package/assets/board/_nuxt/D6dUp4Nm.js +9 -0
  214. package/assets/board/_nuxt/DFQDFspC.js +1 -0
  215. package/assets/board/_nuxt/DHX2tw9J.js +1 -0
  216. package/assets/board/_nuxt/DJM7u8P3.js +1 -0
  217. package/assets/board/_nuxt/{BPTrRhcw.js → DLr85ebo.js} +1 -1
  218. package/assets/board/_nuxt/DOMM1wfl.js +1 -0
  219. package/assets/board/_nuxt/DU6ArlUN.js +1 -0
  220. package/assets/board/_nuxt/{B_SlFcWp.js → DUgGsde6.js} +1 -1
  221. package/assets/board/_nuxt/DV4ti-Pq.js +1 -0
  222. package/assets/board/_nuxt/D_ct-Stz.js +2 -0
  223. package/assets/board/_nuxt/DbWAComO.js +1 -0
  224. package/assets/board/_nuxt/DbwlcHAt.js +1 -0
  225. package/assets/board/_nuxt/Dki9VkAL.js +3 -0
  226. package/assets/board/_nuxt/DlNJhOoc.js +1 -0
  227. package/assets/board/_nuxt/Dmg78zOY.js +3 -0
  228. package/assets/board/_nuxt/DqG7CtD4.js +1 -0
  229. package/assets/board/_nuxt/DqUSsCJ2.js +1 -0
  230. package/assets/board/_nuxt/Du2F4WXh.js +1 -0
  231. package/assets/board/_nuxt/DuRiEXn4.js +1 -0
  232. package/assets/board/_nuxt/DwCE3305.js +1 -0
  233. package/assets/board/_nuxt/DwzGxoX2.js +1 -0
  234. package/assets/board/_nuxt/DxBwVNyP.js +2 -0
  235. package/assets/board/_nuxt/DzmVW5-D.js +1 -0
  236. package/assets/board/_nuxt/I-sGtDIB.js +6 -0
  237. package/assets/board/_nuxt/JU9-x68N.js +1 -0
  238. package/assets/board/_nuxt/Lozm7hhE.js +1 -0
  239. package/assets/board/_nuxt/MMsTMkcB.js +1 -0
  240. package/assets/board/_nuxt/MS7CGmCB.js +1 -0
  241. package/assets/board/_nuxt/OKKaKILz.js +1 -0
  242. package/assets/board/_nuxt/{Csqgy925.js → P6qlvBHA.js} +1 -1
  243. package/assets/board/_nuxt/SrNUvNwO.js +1 -0
  244. package/assets/board/_nuxt/{DSaWoFHS.js → SywdkA98.js} +1 -1
  245. package/assets/board/_nuxt/TBIRpVLG.js +1 -0
  246. package/assets/board/_nuxt/TlTrMIMm.js +1 -0
  247. package/assets/board/_nuxt/Utb4TVOl.js +1 -0
  248. package/assets/board/_nuxt/Zv9-SOQF.js +1 -0
  249. package/assets/board/_nuxt/_id_.B6iqDPxe.css +1 -0
  250. package/assets/board/_nuxt/b7xtxFRl.js +1 -0
  251. package/assets/board/_nuxt/builds/latest.json +1 -1
  252. package/assets/board/_nuxt/builds/meta/08bebe14-0f1b-4d2a-8de4-e84e122d10e9.json +1 -0
  253. package/assets/board/_nuxt/diagrams.pyhqNtmr.css +1 -0
  254. package/assets/board/_nuxt/{entry.CKHePurH.css → entry.BBv-sBnP.css} +1 -1
  255. package/assets/board/_nuxt/error-404.CgJNdpB5.css +1 -0
  256. package/assets/board/_nuxt/error-500.WYSoH44y.css +1 -0
  257. package/assets/board/_nuxt/jbri6q1p.js +1 -0
  258. package/assets/board/_nuxt/q_8bxRMt.js +1 -0
  259. package/assets/board/burndown/index.html +1 -1
  260. package/assets/board/diagrams/index.html +1 -0
  261. package/assets/board/epics/index.html +1 -1
  262. package/assets/board/gantt/index.html +1 -1
  263. package/assets/board/index.html +1 -1
  264. package/assets/board/last-change/index.html +1 -1
  265. package/assets/board/milestones/index.html +1 -1
  266. package/assets/board/tests/index.html +1 -1
  267. package/bin/scrum-skills.mjs +13 -0
  268. package/package.json +2 -1
  269. package/templates/AGENTS.md +10 -0
  270. package/tools/diagram-import.mjs +238 -0
  271. package/tools/diagram-lint.mjs +518 -0
  272. package/tools/diagram.mjs +299 -0
  273. package/tools/last-change.mjs +326 -326
  274. package/tools/projects.mjs +29 -4
  275. package/tools/serve.mjs +27 -1
  276. package/tools/validate.mjs +781 -664
  277. package/assets/board/_nuxt/1eqboJxR.js +0 -1
  278. package/assets/board/_nuxt/2K7ag6ES.js +0 -1
  279. package/assets/board/_nuxt/51OWHj8c.js +0 -2
  280. package/assets/board/_nuxt/6gFtTBwm.js +0 -1
  281. package/assets/board/_nuxt/B3jkABw9.js +0 -1
  282. package/assets/board/_nuxt/B5n2_jZN.js +0 -1
  283. package/assets/board/_nuxt/BDK2Hj7B.js +0 -1
  284. package/assets/board/_nuxt/BDcnzXHq.js +0 -1
  285. package/assets/board/_nuxt/BaG8y0Wt.js +0 -1
  286. package/assets/board/_nuxt/BbwJq5pb.js +0 -1
  287. package/assets/board/_nuxt/BgLeKwx0.js +0 -1
  288. package/assets/board/_nuxt/Bi9Axj3V.js +0 -1
  289. package/assets/board/_nuxt/BmxvtaMq.js +0 -1
  290. package/assets/board/_nuxt/BodFvto3.js +0 -1
  291. package/assets/board/_nuxt/BpWeHLuN.js +0 -1
  292. package/assets/board/_nuxt/BuOKDFiJ.js +0 -1
  293. package/assets/board/_nuxt/C40iTe-x.js +0 -1
  294. package/assets/board/_nuxt/C7K0R7F-.js +0 -2
  295. package/assets/board/_nuxt/C8vL692X.js +0 -1
  296. package/assets/board/_nuxt/C9StZL3D.js +0 -3
  297. package/assets/board/_nuxt/CGI_ZV79.js +0 -1
  298. package/assets/board/_nuxt/CJ2mz0WY.js +0 -1
  299. package/assets/board/_nuxt/CJMBJQuf.js +0 -1
  300. package/assets/board/_nuxt/CK-lOYG9.js +0 -1
  301. package/assets/board/_nuxt/CK9_veoz.js +0 -1
  302. package/assets/board/_nuxt/CLBcBrYf.js +0 -1
  303. package/assets/board/_nuxt/CMUi2-Lj.js +0 -1
  304. package/assets/board/_nuxt/COf6E6h4.js +0 -1
  305. package/assets/board/_nuxt/CPCUMJnF.js +0 -1
  306. package/assets/board/_nuxt/CPcKlmSm.js +0 -1
  307. package/assets/board/_nuxt/CQTvWh4i.js +0 -1
  308. package/assets/board/_nuxt/CSEEUF8S.js +0 -1
  309. package/assets/board/_nuxt/CSSb154I.js +0 -13
  310. package/assets/board/_nuxt/CgDTd7jS.js +0 -1
  311. package/assets/board/_nuxt/ChG76uh9.js +0 -1
  312. package/assets/board/_nuxt/Ci0qbkgh.js +0 -1
  313. package/assets/board/_nuxt/CqoQ__I_.js +0 -1
  314. package/assets/board/_nuxt/CuJUHLl8.js +0 -1
  315. package/assets/board/_nuxt/CvLiA4_O.js +0 -1
  316. package/assets/board/_nuxt/Cvs12oA0.js +0 -3
  317. package/assets/board/_nuxt/CyEXFe3V.js +0 -1
  318. package/assets/board/_nuxt/Cz6rZcLK.js +0 -1
  319. package/assets/board/_nuxt/D2FhHl1o.js +0 -1
  320. package/assets/board/_nuxt/D3YCAmfu.js +0 -1
  321. package/assets/board/_nuxt/D5CE81jK.js +0 -1
  322. package/assets/board/_nuxt/D75vbfSb.js +0 -1
  323. package/assets/board/_nuxt/D99LbGfb.js +0 -9
  324. package/assets/board/_nuxt/DEfLc7p3.js +0 -6
  325. package/assets/board/_nuxt/DF-nsa1Z.js +0 -1
  326. package/assets/board/_nuxt/DIc8yx98.js +0 -1
  327. package/assets/board/_nuxt/DLkAKotw.js +0 -1
  328. package/assets/board/_nuxt/DRPlYvb3.js +0 -1
  329. package/assets/board/_nuxt/DRlQgul3.js +0 -1
  330. package/assets/board/_nuxt/DSLbmoWa.js +0 -1
  331. package/assets/board/_nuxt/DWO9c9yp.js +0 -1
  332. package/assets/board/_nuxt/DZo3dYLJ.js +0 -3
  333. package/assets/board/_nuxt/D_S6N7_b.js +0 -1
  334. package/assets/board/_nuxt/DajA-Tkt.js +0 -1
  335. package/assets/board/_nuxt/DbHiyab-.js +0 -1
  336. package/assets/board/_nuxt/Dc7Ql6eE.js +0 -1
  337. package/assets/board/_nuxt/Dd9ZukPU.js +0 -1
  338. package/assets/board/_nuxt/Dg2LiqmN.js +0 -1
  339. package/assets/board/_nuxt/DhuleNnm.js +0 -1
  340. package/assets/board/_nuxt/DkI1Qxpp.js +0 -95
  341. package/assets/board/_nuxt/DnDHGSYI.js +0 -1
  342. package/assets/board/_nuxt/DpXJ_tCU.js +0 -1
  343. package/assets/board/_nuxt/DqZgF3hU.js +0 -1
  344. package/assets/board/_nuxt/DqcxvfbD.js +0 -1
  345. package/assets/board/_nuxt/DsA2lVci.js +0 -1
  346. package/assets/board/_nuxt/Dtsa-1NS.js +0 -1
  347. package/assets/board/_nuxt/Du91iq0p.js +0 -1
  348. package/assets/board/_nuxt/Dx1wcYFo.js +0 -1
  349. package/assets/board/_nuxt/EYTShbt4.js +0 -1
  350. package/assets/board/_nuxt/MaXJprwN.js +0 -1
  351. package/assets/board/_nuxt/P9x67aq2.js +0 -1
  352. package/assets/board/_nuxt/S08nFESZ.js +0 -3
  353. package/assets/board/_nuxt/V0uynWE2.js +0 -1
  354. package/assets/board/_nuxt/Vo4wMbnS.js +0 -1
  355. package/assets/board/_nuxt/ZVTqot-_.js +0 -1
  356. package/assets/board/_nuxt/ZngEd3HB.js +0 -1
  357. package/assets/board/_nuxt/_id_.B2NDKSlX.css +0 -1
  358. package/assets/board/_nuxt/assMu_Wn.js +0 -1
  359. package/assets/board/_nuxt/builds/meta/8e23aec9-5b67-4569-b8bf-d4f07e50ffdf.json +0 -1
  360. package/assets/board/_nuxt/error-404.BFmXOnCT.css +0 -1
  361. package/assets/board/_nuxt/error-500.BZ-DdjQ6.css +0 -1
  362. package/assets/board/_nuxt/rlePnzpc.js +0 -1
  363. package/assets/board/_nuxt/uKzCKCTq.js +0 -1
  364. package/assets/board/_nuxt/vwxaNGfc.js +0 -1
  365. package/assets/board/_nuxt/yh6sf_D5.js +0 -1
@@ -0,0 +1,117 @@
1
+ # Architecture
2
+
3
+ **Best for:** system overviews, data-flow diagrams, integration maps, infra topology.
4
+
5
+ ## Layout conventions
6
+ - Group components by tier or trust boundary (frontend → backend → data; public → private).
7
+ - Primary flow runs left→right or top→down. Pick one and hold it.
8
+ - Draw arrows before boxes so z-order puts connections behind components.
9
+ - 1–2 coral focal nodes: the primary integration point, the primary data store, or the key decision node.
10
+ - Dashed boundary rectangles mark regions (VPC, security group, trust zone); labels sit on a paper-colored mask over the boundary line.
11
+
12
+ ## Connector style
13
+
14
+ **Rounded right-angle (orthogonal) connectors are MANDATORY** for all non-horizontal/vertical connections — diagonal `<line>` between off-axis nodes is a hard fail (see SKILL.md §6 Mandatory connector rules). Two-bend elbow path with `r=8`:
15
+
16
+ ```svg
17
+ <!-- right+down: from (x1,y1) to (x2,y2), mid = (x1+x2)/2 -->
18
+ <path d="M x1,y1 H mid-8 Q mid,y1 mid,y1+8 V y2-8 Q mid,y2 mid+8,y2 H x2"
19
+ fill="none" stroke="…" stroke-width="1.2" marker-end="url(#arrow)"/>
20
+ ```
21
+
22
+ Flip the vertical signs for right+up. Use a plain `<line>` only when endpoints share the same x or y. Arrow labels sit on the vertical segment, centered horizontally on `mid` and vertically between the two corners.
23
+
24
+ **Port selection for vertical connectors.** When the destination is noticeably above or below the source, enter the destination through its top or bottom edge. Use a single-bend L-path: leave the source through the side edge that faces the destination's column, run horizontally, turn once, and run vertically into the destination:
25
+
26
+ ```svg
27
+ <!-- destination above source: leave the source's right edge at (x_right, y_port), enter the destination's bottom edge at x2 -->
28
+ <path d="M x_right,y_port H x2-8 Q x2,y_port x2,y_port-8 V y_dst"
29
+ fill="none" stroke="…" stroke-width="1.2" marker-end="url(#arrow)"/>
30
+ ```
31
+
32
+ Every segment leaves its box perpendicular to the edge it starts on. Never start a horizontal segment on a top or bottom edge: it runs along the border, hidden behind the node fill, and the arrow looks like it grows out of the corner. When two of these connectors leave the same side edge, fan their ports (primitives-core.md rule 4) and keep each port at least 8px from a corner so it never lands on the corner radius.
33
+
34
+ Reserve left/right ports on the destination for connections that travel primarily horizontally. Entering a node from the side on a mainly-vertical path looks like the arrow punctures the node face rather than arriving from above or below.
35
+
36
+ **Dashed paths — same routing rules.** Optional, return, async, and passive flows use `stroke-dasharray="4,3"` and a lighter stroke weight (`stroke-width="1"`). Apply the **same orthogonal routing, port-selection, and bridge/hop rules** as solid paths — the dash pattern only communicates semantic weight, not a different routing grammar. When a dashed path and a solid path must cross, bridge the dashed one (it is by definition the less important connection).
37
+
38
+ **Zone label margin.** Leave ≥16px between the bottom of the zone eyebrow label and the top of the first enclosed node. Size the zone rect tall enough to contain this header gap (zone `y` = node_top − 32; label mask `y` = zone_y + 4).
39
+
40
+ ## Crossing arrows — bridge / hop
41
+
42
+ When two orthogonal arrows must cross, add a small arc (hop/bridge) on the **less important** arrow at the crossing point. The more important arrow is drawn uninterrupted.
43
+
44
+ ```svg
45
+ <!-- Horizontal hop over a vertical crossing at x=cx, on a line at y -->
46
+ <path d="M x1,y H cx-8 a 8,8 0 0,1 16,0 H x2"
47
+ fill="none" stroke="…" stroke-width="1.2" marker-end="url(#arrow)"/>
48
+ ```
49
+
50
+ `a 8,8 0 0,1 16,0` is an SVG arc: rx=ry=8, large-arc=0, sweep=1 (curves visually upward), advancing 16px right — creating an 8px-radius semicircular bump over the crossing. For a vertical hop over a horizontal, use `a 8,8 0 0,0 0,16` on the vertical path.
51
+
52
+ Decide which arrow to bridge: bridge the one that is less semantically important (passive, secondary, write-back), or the one with lighter stroke weight (dashed, muted). Never bridge both.
53
+
54
+ ## Zone grouping
55
+
56
+ Group 2+ nodes that serve the same tier or trust boundary with a zone rect — drawn **before** arrows and nodes (z-order: bg → zones → arrows → nodes):
57
+
58
+ ```svg
59
+ <rect x="{x}" y="{y}" width="{w}" height="{h}" rx="8"
60
+ fill="{ink @ 0.02}" stroke="{ink @ 0.10}" stroke-width="0.8"/>
61
+ <rect x="{label_x}" y="{y+4}" width="{label_w}" height="12" rx="2" fill="{paper}"/>
62
+ <text x="{label_cx}" y="{y+13}" fill="{soft}" font-size="7"
63
+ font-family="{eyebrow}" text-anchor="middle" letter-spacing="0.14em">LAYER</text>
64
+ ```
65
+
66
+ Rules:
67
+ - Leave 12–16px above the first enclosed node — the eyebrow label sits in this margin.
68
+ - Zone fill: `ink @ 0.02` (2% ink wash). Any stronger competes with node fills.
69
+ - **Zone label: `soft`, never ink at an opacity.** A zone eyebrow is a boundary label, and `soft` is the boundary-label role in [`style-guide.md`](style-guide.md). An opacity such as `ink @ 0.40` composites differently on every `paper`; on a light warm paper it falls near 2.2:1, unreadable at 7px. The role carries its own contrast contract under any skin.
70
+ - Max 3 **flat** zones per diagram. More and it reads like a swimlane (use that type instead). Nested administrative and traffic scopes under **Containment** below are not this cap — they nest, so the cap is sibling traffic scopes at one level.
71
+ - Dark mode: the roles invert with the skin, so nothing is swapped by hand. Take `ink`, `soft`, and `paper` from the dark column in [`style-guide.md`](style-guide.md); opacities stay the same.
72
+
73
+ ## Containment
74
+
75
+ Use this section when **the network hierarchy itself carries the meaning** — the reader must see what sits inside which scope, and a flattened zone label (`VNET · SNET-APP`) would lie about that hierarchy. Connectors stay Architecture; containment geometry comes from Nested (consistent insets, eyebrow per level, fills stepping up inward). This is a variant of Architecture, not a new type and not a provider-specific grammar.
76
+
77
+ Two scope kinds, never interchangeable:
78
+
79
+ | Kind | What it is | Shape | `data-scope-kind` |
80
+ |---|---|---|---|
81
+ | **Administrative** | Billing, permissions, lifecycle. Holds no traffic. | Horizontal **band** — a full-width containment rect with a 24px header | `admin` |
82
+ | **Traffic** | A boundary packets do not cross without an explicit rule. | **Box** — the existing zone rect (`rx=8`) | `traffic` |
83
+
84
+ Provider-neutral metadata (no vendor prefix):
85
+
86
+ - `data-grammar="architecture-containment"` on the root `<svg>` — files without it are ordinary Architecture and this contract does not apply.
87
+ - `data-scope-id` + `data-scope-kind` on every scope's bounds rect (`data-role="bounds"`). Bounds are always a `<rect>`, for scopes and nodes alike.
88
+ - `data-parent` on every nested scope and every node, naming the innermost enclosing `data-scope-id`. Only the outermost scope, which no other scope encloses, may omit it.
89
+ - Nodes: `data-node-id`, `data-kind` of `compute` (workloads inside a traffic scope), `endpoint` (private endpoint inside a traffic scope), or `managed` (PaaS that belongs to an administrative scope).
90
+ - An `endpoint` carries `data-target` naming the `managed` node it reaches.
91
+ - A peering path carries `data-peering`, `data-from`, and `data-to` naming the two traffic scopes it joins.
92
+
93
+ **PaaS placement (normative).** A managed service is never inside a traffic scope. It sits in the administrative band that owns it. What lives in the subnet is its private endpoint. Drawing a database inside a subnet tells the reader it sits behind that subnet's security rules, which it does not. `scripts/verify-architecture-containment.py` fails a `managed` node whose bounds fall inside any `traffic` scope, and an `endpoint` that is not inside one.
94
+
95
+ **Sibling axis.** Sibling traffic scopes at one level share one axis. Directly under an administrative band the parent's aspect chooses it: wider than tall (or square) → a row sharing one `y`; taller than wide → a column sharing one `x`. Nested children take the perpendicular axis: siblings inside a traffic scope that sits in a row form a column, and their own children form a row again. Do not mix axes at one level.
96
+
97
+ **Budget** (tightens Architecture's flat 3-zone cap; see `layout-budget.md`): ≤2 administrative bands, ≤4 traffic scopes, ≤8 nodes, 2 accent elements. Split per subscription when a figure exceeds that.
98
+
99
+ **Draw scopes in place.** Containment is read from each bounds rect's own `x`, `y`, `width`, and `height`. Do not position a scope or node with a `transform` attribute, a moving inline style (`transform`, `translate`, `x`, `y`, `position`, `margin`, and similar), a nested `<svg>`, a `<style>` rule, or an animation, on the element or any group around it. The checker fails each of those. It does not evaluate external stylesheets or script, so keep containment geometry out of both.
100
+
101
+ `scripts/verify-architecture-containment.py` checks unique IDs, resolving innermost parents, geometric containment, `<rect>` bounds, the admin-band vs traffic-box shapes (with `stroke-dasharray` resolved as rendered, so `none` or all-zero dashes count as solid), PaaS placement, endpoint targets, sibling axes, declared peerings, and the moved-geometry rule above. Files without `data-grammar="architecture-containment"` are skipped.
102
+
103
+ ## Anti-patterns
104
+ - Every box in coral ("this is important too") — hierarchy collapses.
105
+ - Bidirectional arrow when one direction is obvious from context.
106
+ - Legend floating inside the diagram area.
107
+ - Flattening two containment levels into one zone eyebrow (`VNET · SNET-APP`) — the hierarchy is the claim.
108
+ - A managed PaaS box drawn inside a subnet or VPC — only its private endpoint belongs there.
109
+ - Colour as the only distinction between an administrative band and a traffic box — the shapes must differ, because greyscale still has to tell them apart.
110
+
111
+ ## Examples
112
+ - `assets/example-architecture.html` — minimal light
113
+ - `assets/example-architecture-dark.html` — minimal dark
114
+ - `assets/example-architecture-full.html` — full editorial
115
+ - `assets/example-architecture-containment.html` — nested admin/traffic scopes, light
116
+ - `assets/example-architecture-containment-dark.html` — nested admin/traffic scopes, dark
117
+ - `assets/example-architecture-containment-full.html` — nested admin/traffic scopes, full editorial
@@ -0,0 +1,83 @@
1
+ # Axonometric plan
2
+
3
+ **Best for:** one floor or one site seen from above at an angle, with what stands on it. An office floor with its rooms and furniture, a campus with its buildings and roads, a warehouse with its zones, a store layout. Use it when the reader needs to see rooms or buildings in relation to each other and how they are used, in a single view.
4
+
5
+ **Not this type:**
6
+
7
+ - Parts of one object pulled apart along an axis → **exploded axonometric** (`type-exploded.md`). A plan has one plate and nothing explodes.
8
+ - Containment without geography → **nested** (`type-nested.md`).
9
+ - Where software runs → **deployment** (`type-deployment.md`).
10
+ - A list of rooms and capacities → a table.
11
+
12
+ ## Projection
13
+
14
+ The same 2:1 dimetric projection as the exploded axonometric, from one function:
15
+
16
+ ```python
17
+ def iso(x, y, z, ox, oy):
18
+ """Model point to SVG point. (ox, oy) is where model (0, 0, 0) lands."""
19
+ return ox + x - y, oy + (x + y) / 2 - z
20
+ ```
21
+
22
+ Every element is a rounded prism standing on the plate: `r = 0` for walls, furniture, and buildings, `r = w / 2` for a tree canopy. `type-exploded.md` § Projection covers the corner ellipse and the face matrices; `scripts/build-axonometric-plan-examples.py` in the repository builds every shipped example from the same helpers.
23
+
24
+ ## Layout conventions
25
+
26
+ - **Plate:** One floor slab (6 units) or one site (8 units, small corner radius). Everything stands on it, and nothing extends past its edge.
27
+ - **Walls:** 6 units thick and cut at desk height, about 22 units, so no wall hides a room. Doors are gaps in a wall. Walls meet without overlapping: run one wall through a junction and stop the other at its face.
28
+ - **Furniture and buildings:** Boxes on the plate with the house face shading (`type-exploded.md` § Faces and lines). Heights are to scale with each other. Two footprints never overlap.
29
+ - **Flat marks:** Roads, paths, and floor tints sit on the plate's top face as flat fills (`ink` at 0.07) with no thickness. A dashed centre line (`ink` at 0.25, `6,5`) may mark a road.
30
+ - **Racks:** Tall shelving is a box of kind `rack` with the house shading, a shelf line every 14 units, and an upright every 30. Run rack rows along x so the reader sees the lit face and the aisles between rows.
31
+ - **Trees:** A canopy cylinder 8 units up on a short trunk, canopy top in `rule-solid` light or `soft` dark. Trees are planting, so keep them small and off every footprint.
32
+ - **Paint order:** The plate first, then flat marks, then every box back to front. Sort with a topological order: box A paints before box B when A lies entirely behind B (`A.x1 <= B.x0` or `A.y1 <= B.y0`) and their screen outlines overlap. A plain `x + y` sort fails on long walls.
33
+ - **Frame:** The canvas is 1000 wide and the plate is centred. The viewBox height follows the plate and its tallest box plus a 48px top margin.
34
+
35
+ ### Tags
36
+
37
+ - Rooms and buildings are named by a horizontal tag: the name in the `node-name` role, 600, 12px, above a sublabel in the `sublabel` role at 8px, on an opaque `paper` backing with a `rule` hairline, 32px tall, width rounded up to a multiple of 4.
38
+ - A room's tag sits on open floor inside the room. A building's tag sits on its roof. Tags paint after every box so walls never cut them.
39
+ - Tags never overlap each other. Move a tag to open floor before you shorten its name.
40
+ - One or two words per name. No leader lines and no numbered key.
41
+
42
+ ### Focal element
43
+
44
+ One room or one building wears the accent. A focal room gets an `accent` tint on its floor and an accent tag; a focal building gets the accent face ramp and an accent tag. Furniture inside a focal room stays neutral, so the accent marks one thing.
45
+
46
+ ## Optional motion
47
+
48
+ A site that is built in phases can reveal its buildings phase by phase with the pinned controller from `assets/template-motion.html` in `reveal` mode. Each building and its tag form one `data-motion-item` whose `data-step` is its phase, at most two per step. Buildings drop 16px into place and fade in, inside the 24px limit in `animation.md`.
49
+
50
+ A floor plan can reveal by zone the same way. Give each zone's furniture a `step`, and the builder paints each phase as one contiguous group of boxes (it contracts a phase to one node in the depth sort, so a phase that would have to paint on both sides of a static wall fails the build) plus one group of that phase's room tags after every box. That is two motion items per phase, inside the limit of two per step. Walls and unphased rooms stay static. The static, no-JavaScript, reduced-motion, print, and export states show the finished site.
51
+
52
+ ## Metadata contract
53
+
54
+ `scripts/verify-axonometric-plan.py` reprojects each element from what it declares:
55
+
56
+ - The figure: one `<g data-axo-plan data-origin="ox oy">`.
57
+ - The plate: one `<g data-plate data-rect="x0 y0 x1 y1 r" data-z="0" data-t="t">`.
58
+ - Each box: a `<g data-box>` with `data-rect`, `data-z` (the plate top, or 8 above it for a tree canopy), `data-h`, `data-kind` (`wall`, `furniture`, `building`, `tree`, `rack`), and for a building `data-name`. Its first path is `data-role="silhouette"`.
59
+ - Each room: a `<g data-room data-name data-rect>`.
60
+ - Each tag: a `<g data-role="tag" data-name data-at="x y z">` with a backing `<rect>` and a `<text data-role="name">`. Its complete text, including inline `<tspan>` descendants, must match the tag's `data-name`. The point sits inside the room it names at the plate top, or on the building's roof.
61
+ - The focal room or building carries `data-focal`.
62
+
63
+ The silhouette verifier accepts signed decimal and scientific-notation coordinates within the existing absolute M/L/A/Z path contract. Every operand must be finite; projected vertices, corner radii, and arc flags are still checked. This does not add relative path commands.
64
+
65
+ ## Anti-patterns
66
+
67
+ - Full-height walls that hide the rooms behind them.
68
+ - Boxes that overlap on the plate, or a box hanging past the plate edge.
69
+ - Painting by `x + y` alone, which draws long walls over the furniture in front of them.
70
+ - Tags tilted onto the floor plane, tags that overlap, or a numbered key under the figure.
71
+ - Accent on the focal room and on its furniture as well.
72
+ - Gradients, shadows, or glow on the plate or the boxes.
73
+
74
+ ## Examples
75
+
76
+ - `assets/example-axonometric-plan.html`: office floor, minimal light
77
+ - `assets/example-axonometric-plan-dark.html`: office floor, minimal dark
78
+ - `assets/example-axonometric-plan-full.html`: office floor, full editorial
79
+ - `assets/example-axonometric-plan-campus.html`, `-dark`, `-full`: campus site plan with roads, trees, and buildings tagged by phase
80
+ - `assets/example-axonometric-plan-coffee-shop.html`, `-dark`, `-full`: a coffee shop with an entrance and queue posts, an espresso bar, round tables, a kitchen, and a restroom
81
+ - `assets/example-axonometric-plan-warehouse.html`, `-dark`, `-full`: a fulfillment floor with dock doors, tall storage racks, a pick zone, packing stations, and shipping docks
82
+ - `assets/example-axonometric-plan-campus-animated.html`: the campus built phase by phase
83
+ - `assets/example-axonometric-plan-coffee-shop-animated.html`, `assets/example-axonometric-plan-warehouse-animated.html`: each floor revealed zone by zone in three phases
@@ -0,0 +1,108 @@
1
+ # Bar / Column Chart
2
+
3
+ **Best for:** comparing discrete quantities across categories or time intervals — sprint velocity, monthly revenue, feature adoption, cohort counts. Use when each category has a single numeric value and the comparison between bars is the primary message — or, in the dumbbell variant below, exactly two values whose difference is the message.
4
+
5
+ ## Layout conventions
6
+
7
+ - **Orientation:** Vertical bars (columns) are default. Horizontal bars are appropriate when category labels are long or you have more than 8 categories.
8
+ - **Plot area margins:** left 80px (y-axis labels), bottom 60px (x-axis labels), top 40px, right 40px — inside a `0 0 1000 500` viewBox.
9
+ - **Bar count cap:** 4–8 bars. More than 8 → group into periods or split into two charts.
10
+ - **Bar width:** ≥ 50% of the column pitch (the gap should never exceed the bar). Typical: pitch=110px, bar=72px.
11
+ - **Y-axis gridlines:** 4–6 horizontal lines at regular intervals. Stroke `ink @ 0.08` (very faint), 0.8px. X-axis baseline at `ink @ 0.25`, 1px.
12
+ - **Y-axis labels:** right-aligned `arrow-label` role 8px in `muted`, at x=72 (8px left of the plot area).
13
+ - **X-axis labels:** centered below each bar, `node-name` role 11px 600 for category names.
14
+ - **Value labels:** `arrow-label` role 8px above each bar. Focal bar label in `accent`; others in `muted`.
15
+ - **Focal bar:** 1 bar max in accent fill/stroke. All others in `muted @ 0.15` fill + `muted` stroke.
16
+ - **Y-axis line:** thin vertical `<line>` at x=80 from y=40 to y=420.
17
+
18
+ ### Bar element pattern
19
+
20
+ ```svg
21
+ <!-- Opaque paper mask prevents bleed from background -->
22
+ <rect x="X" y="Y" width="W" height="H" fill="{paper}"/>
23
+ <!-- Bar body -->
24
+ <rect x="X" y="Y" width="W" height="H" fill="{muted @ 0.15}" stroke="{muted}" stroke-width="1"/>
25
+ <!-- Value label above bar -->
26
+ <text x="X+W/2" y="Y-8" fill="{muted}" font-size="8" font-family="{arrow-label}" text-anchor="middle">VALUE</text>
27
+ ```
28
+
29
+ Focal bar: replace fill with `accent @ 0.12`, stroke with `accent`, label fill with `accent`.
30
+
31
+ ## Anti-patterns
32
+
33
+ - More than 8 bars without grouping (illegible at normal scale).
34
+ - Truncated y-axis (not starting at 0) — distorts the magnitude comparison.
35
+ - Accent on more than 1 bar ("everything is important" = nothing is).
36
+ - 3-D bar extrusion — no shadows, no depth.
37
+ - Category labels rotated more than 45°; prefer short labels or horizontal chart instead.
38
+
39
+ ## Variants
40
+
41
+ - **Grouped bars:** two bars per category, side by side. Use `accent` for the primary series and `series-1` for the secondary. Max 2 groups.
42
+ - **Stacked bars:** segments stacked to total. Use `accent` for the focal segment; muted tints for others. Document the total at the top of each stack.
43
+ - **Dumbbell:** one row per category, two dots on a single shared horizontal scale joined by a hairline. Use it for a two-state comparison where the *distance* between the ends is the message — before/after, two cohorts, target vs actual. Two series only; a third dot makes the connector meaningless and the figure is a dot plot.
44
+
45
+ ### Dumbbell layout
46
+
47
+ - **Orientation:** horizontal only. Rows stack downward and the value axis runs left → right; a vertical dumbbell forces rotated category labels.
48
+ - **Plot area:** left margin 200px for row labels — this replaces the 80px margin above — so `x` 200→960, `y` 40→420 inside `0 0 1000 500`. Row labels right-aligned at x=188, `node-name` role 11px 600 `ink` (the category-label size this type already uses).
49
+ - **Rows:** the 4–8 bar count cap applies. Pitch and origin are fixed per row count so the block stays inside the plot band — a 64px pitch from y=96 overflows y=420 at seven rows:
50
+
51
+ | rows | pitch | first row `y` | last row `y` |
52
+ | --- | --- | --- | --- |
53
+ | 4 | 88 | 96 | 360 |
54
+ | 5 | 64 | 96 | 352 |
55
+ | 6 | 64 | 76 | 396 |
56
+ | 7 | 52 | 72 | 384 |
57
+ | 8 | 48 | 68 | 404 |
58
+
59
+ - **Gridlines:** vertical at each tick, `ink @ 0.08` 0.8px, spanning y 56→408. At the domain floor the axis line replaces the gridline rather than doubling it: `ink @ 0.25` 1px, y 40→420.
60
+ - **Tick labels:** centered under each gridline at y=440, `arrow-label` role 8px `muted`.
61
+ - **Axis title:** the value axis carries the family's axis label — `eyebrow` role 7px `muted`, `letter-spacing="0.14em"`, centered at x=580, y=456, below the tick labels and clear of the legend rule. A horizontal axis takes the un-rotated form the scatter x-axis uses, not the `rotate(-90 24 230)` form the column charts apply to their y-axis. The category axis needs no title: the row labels name themselves.
62
+ - **Dots:** r=6, positioned by value. Style by *series*: the reference end hollow (paper fill, `muted` stroke 1.5px), the focal end solid `accent` with a 1px `ink` stroke. Both marks therefore have a boundary above 3:1 even though the accent fill is not — see below. Fill weight, not hue, carries the pairing.
63
+ - **Accent marks the series, not a focal row.** The solid dot repeats on every row — the one place this variant departs from the one-accent rule above, because the two ends must be told apart in each pair. Do not additionally accent a "most changed" row; the sort order already carries rank.
64
+ - **Connector:** `ink @ 0.55` 1px (`rgba(45,49,66,0.55)` under the default light skin, the value `scripts/verify-dumbbell.py` checks), declared before both dots so the dots cap it. It is not the axis hairline: the connector is what says *these two dots are one row*, so it has to clear 3:1 (0.55 gives 3.19:1; the 0.25 the axis uses gives 1.60:1).
65
+ - **Endpoint positions round, they never snap.** `x = 200 + (v − floor) ÷ (ceil − floor) × 760`, with `floor` and `ceil` set by the axis rule below, rounded to the nearest integer pixel — at most 0.5px, below one rendered pixel. Data coordinates are exempt from the 4px grid; snapping them moves the data.
66
+ - **Value labels sit outside the pair, placed by geometry rather than by series.** A focal value *below* its reference reverses the dots, so derive `x_left = min(x_ref, x_focal)` and `x_right = max(x_ref, x_focal)`: left label right-anchored at `x_left − 12`, right label left-anchored at `x_right + 12`, both baseline `y + 4`, `arrow-label` role 8px `muted`, each still carrying its own series' value. Keying the offsets to start/end instead puts both labels *inside* the pair on every decreasing row.
67
+ - **Floor exception.** A value sitting on the domain floor lands its label at x=188, right-anchored on baseline `y + 4` — exactly the category label's anchor and baseline, so the two texts overlap. When `x_left − 12 < 200`, centre that label above its dot at baseline `y − 10` instead.
68
+ - **Legend:** two keys on the legend row — hollow dot, then solid dot, each with its series name. Circular keys centre at `cy=493`, the centre of the bar legend's 10px key rect at y=488, so both sit on the 497 text baseline. The row order goes in the legend or the source line, right-aligned on the same row.
69
+
70
+ **Why the dots differ by fill, not hue.** The focal bar pattern above (12% tint + accent stroke) does not transfer to a 6px dot: the 12% tint across a 6px-radius disc contributes roughly 14 square pixels of colour, so the mark reads as its stroke alone and the pair separates by hue only. A solid accent dot against a hollow one separates by shape, survives greyscale and colour-vision deficiency, and leaves hue as redundant encoding.
71
+
72
+ **Non-text contrast: the boundary carries it, not the fill.** The default accent clears the 3:1 WCAG 1.4.11 asks of a graphical object (4.71:1 on light paper, 5.21:1 on dark), but an onboarded accent may not, and shape redundancy does not waive that floor, because the reader still has to see the mark's edge and the line joining the pair. So neither is left to the accent: the solid endpoint takes a 1px `ink` stroke (11.82:1 against paper) and the connector takes 55% ink on light, 40% on dark (3.19:1 and 3.24:1). The hollow end already cleared it via its `muted` stroke at 6.11:1 light and 7.07:1 dark. `scripts/verify-dumbbell.py` asserts all four, so a later tint change cannot quietly drop one under the line. The hollow/solid shape difference stays as redundant encoding for greyscale and colour-vision deficiency — do not collapse the two dots to a single fill.
73
+
74
+ **Minimum drawn gap — never clamp it.** Both dots carry `r="6"`; the hollow one paints out to 6.75 because its 1.5px stroke straddles the path, so the marks touch at 12.75px of centre separation and below about 16px the pair reads as one blob — on a 0–100 domain across 760px, a data gap of 2.1 units. Do **not** widen the separation to clear it: moving a dot off its scaled position breaks the shared-scale rule below. Keep the true positions and shrink both marks (r=4 touches at 8.75px), or print the two values and mark the row as too close to resolve.
75
+
76
+ ### Dumbbell element pattern
77
+
78
+ ```svg
79
+ <!-- One row. Connector first so the dots cap it; labels outside the pair. -->
80
+ <line x1="458" y1="96" x2="740" y2="96" stroke="{ink @ 0.55}" stroke-width="1"/>
81
+ <circle cx="458" cy="96" r="6" fill="{paper}" stroke="{muted}" stroke-width="1.5"/>
82
+ <circle cx="740" cy="96" r="6" fill="{accent}" stroke="{ink}" stroke-width="1"/>
83
+ <text x="446" y="100" fill="{muted}" font-size="8" font-family="{arrow-label}" text-anchor="end">34</text>
84
+ <text x="752" y="100" fill="{muted}" font-size="8" font-family="{arrow-label}">71</text>
85
+ <text x="188" y="100" fill="{ink}" font-size="11" font-weight="600" font-family="{node-name}" text-anchor="end">Platform</text>
86
+ ```
87
+
88
+ Values 34 and 71 on a 0–100 domain compute to 458.4 and 739.6, rounded to 458 and 740. Had this row fallen instead, the accent dot would sit on the left; the two anchors stay tied to left and right, and each label carries its own series' value.
89
+
90
+ **Dark theme.** Dots and labels keep their roles and take the dark column of [`style-guide.md`](style-guide.md): hollow `paper` fill with a `muted` stroke, solid `accent` with an `ink` stroke, labels `muted`. **The hairline opacities change too:** gridlines `ink @ 0.08`, axis `ink @ 0.20`, connector `ink @ 0.40` (`rgba(245,245,245,0.40)` under the default dark skin). The connector stays heavier than the axis, for the same 3:1 reason. Resolve `ink` against the dark column, never the light one: in the default skin light `ink` *is* dark `paper`, so a connector, gridline, or axis carried over from light composites to exactly 1.000:1 and the gap encoding and the scale both vanish.
91
+
92
+ ### Dumbbell honesty rules
93
+
94
+ - **Never truncate the value axis.** `floor` and `ceil` follow the data's range, never its observed extremes — taking `min` and `max` as the bounds *is* the truncation. With `lo` and `hi` the smallest and largest values, the four cases are exhaustive: `lo >= 0` anchors `floor = 0` and rounds `ceil` up past `hi` (including fractional data smaller than a fixed absolute tolerance); `hi <= 0` anchors `ceil = 0` and rounds `floor` down past `lo`; `lo < 0 < hi` brackets both sides, and zero then falls inside the plot — give it a line at its scaled position in the axis-line weight, since it is what every gap is read against. The fourth case is the one a sign-based rule drops: **when every value is zero**, `lo == hi == 0` would make `ceil - floor` zero and the position formula divide by zero, so take a finite fallback span (`floor = 0`, `ceil = 1` in the data's unit) and let every dot sit on the floor, which is the truth. Data that merely *touches* zero is covered by the first two cases, not a special one. `scripts/verify-dumbbell.py` implements this and proves finite coordinates for all four. The plot width is fixed, so narrowing the domain raises px-per-unit and draws every gap wider: across the same 760px, an 8-point gap is 61px on a 0–100 axis and 152px on a 40–80 axis. Ratios *between* rows survive the zoom — what inflates is each gap's size against the frame, which is how a reader judges whether a gap is large. The gap is the entire claim, which makes this the most common way a dumbbell lies.
95
+ - **Both dots share one scale and one unit.** Label both endpoints with their real values. Labelling only the focal end asks the reader to take the geometry on trust.
96
+ - **The connector is a gap, not a trajectory.** It encodes the distance between two values and nothing about what lies between them — no intermediate points, no rate, no guarantee the change was monotonic. Do not narrate it as movement.
97
+ - **State the row order** in the legend or source line: by one endpoint, by signed change, by absolute change, or by an order the subject supplies (chronological, geographic, ordinal). "By gap" alone is ambiguous — say signed or absolute. What is not allowed is an unstated order, which reads as arbitrary.
98
+ - **A row missing an endpoint is disclosed, never imputed and never silently dropped.** Removing incomplete categories without saying so changes the population being compared. Either draw the known end and name the missing value, or drop the row *and* record which rows went and why — a lone dot is otherwise indistinguishable from two coincident dots, which is to say from a genuine zero gap.
99
+
100
+ Two of these rules live in a formula rather than a drawing, so they are executable: `scripts/verify-dumbbell.py` resolves the domain over every sign case and asserts finite coordinates and 3:1 marks, and `scripts/test-verify-dumbbell.py` exercises both polarities — including all-zero and zero-touching data, and the sub-3:1 treatments this replaced. The checker reads the tokens out of this file, so prose and thresholds cannot drift apart. A shipped dumbbell example would additionally owe a check of drawn positions against the values printed at them.
101
+
102
+ ## Examples
103
+
104
+ - `assets/example-bar.html` — minimal light
105
+ - `assets/example-bar-dark.html` — minimal dark
106
+ - `assets/example-bar-full.html` — full editorial
107
+
108
+ Dumbbell domain resolution retains finite bounds for representable subnormal and extreme values. If the next nice ladder step would overflow, the finite extreme is used; opposite-sign extreme domains are scaled without overflowing their span.