@starci/skills 1.1.0

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 (321) hide show
  1. package/INDEX.md +74 -0
  2. package/INDEX.vi.md +75 -0
  3. package/README.md +44 -0
  4. package/README.vi.md +43 -0
  5. package/SKILL.md +135 -0
  6. package/SKILL.vi.md +128 -0
  7. package/alias/INDEX.md +104 -0
  8. package/alias/INDEX.vi.md +104 -0
  9. package/alias/alias.json +297 -0
  10. package/bin/starci-skills.mjs +219 -0
  11. package/knowledge/INDEX.md +22 -0
  12. package/knowledge/INDEX.vi.md +22 -0
  13. package/knowledge/grammars/starci/DNA.md +146 -0
  14. package/knowledge/grammars/starci/DNA.vi.md +146 -0
  15. package/knowledge/grammars/starci/INDEX.md +25 -0
  16. package/knowledge/grammars/starci/INDEX.vi.md +25 -0
  17. package/knowledge/grammars/starci/family.md +50 -0
  18. package/knowledge/grammars/starci/family.vi.md +50 -0
  19. package/knowledge/grammars/starci/idioms.md +120 -0
  20. package/knowledge/grammars/starci/idioms.vi.md +121 -0
  21. package/knowledge/grammars/starci/playbook.md +36 -0
  22. package/knowledge/grammars/starci/playbook.vi.md +35 -0
  23. package/knowledge/patterns/be/INDEX.md +29 -0
  24. package/knowledge/patterns/be/INDEX.vi.md +29 -0
  25. package/knowledge/patterns/be/comment.md +80 -0
  26. package/knowledge/patterns/be/comment.vi.md +80 -0
  27. package/knowledge/patterns/be/error.md +86 -0
  28. package/knowledge/patterns/be/error.vi.md +86 -0
  29. package/knowledge/patterns/be/folder.md +87 -0
  30. package/knowledge/patterns/be/folder.vi.md +86 -0
  31. package/knowledge/patterns/be/function.md +80 -0
  32. package/knowledge/patterns/be/function.vi.md +80 -0
  33. package/knowledge/patterns/be/imports.md +79 -0
  34. package/knowledge/patterns/be/imports.vi.md +79 -0
  35. package/knowledge/patterns/be/naming.md +87 -0
  36. package/knowledge/patterns/be/naming.vi.md +87 -0
  37. package/knowledge/patterns/be/test.md +79 -0
  38. package/knowledge/patterns/be/test.vi.md +79 -0
  39. package/knowledge/patterns/be/typing.md +73 -0
  40. package/knowledge/patterns/be/typing.vi.md +73 -0
  41. package/knowledge/patterns/fe/INDEX.md +29 -0
  42. package/knowledge/patterns/fe/INDEX.vi.md +29 -0
  43. package/knowledge/patterns/fe/comment.md +70 -0
  44. package/knowledge/patterns/fe/comment.vi.md +70 -0
  45. package/knowledge/patterns/fe/error.md +61 -0
  46. package/knowledge/patterns/fe/error.vi.md +61 -0
  47. package/knowledge/patterns/fe/folder.md +98 -0
  48. package/knowledge/patterns/fe/folder.vi.md +95 -0
  49. package/knowledge/patterns/fe/function.md +70 -0
  50. package/knowledge/patterns/fe/function.vi.md +70 -0
  51. package/knowledge/patterns/fe/imports.md +87 -0
  52. package/knowledge/patterns/fe/imports.vi.md +87 -0
  53. package/knowledge/patterns/fe/naming.md +77 -0
  54. package/knowledge/patterns/fe/naming.vi.md +77 -0
  55. package/knowledge/patterns/fe/test.md +73 -0
  56. package/knowledge/patterns/fe/test.vi.md +73 -0
  57. package/knowledge/patterns/fe/typing.md +67 -0
  58. package/knowledge/patterns/fe/typing.vi.md +67 -0
  59. package/knowledge/ui/INDEX.md +101 -0
  60. package/knowledge/ui/INDEX.vi.md +101 -0
  61. package/knowledge/ui/composition/INDEX.md +60 -0
  62. package/knowledge/ui/composition/INDEX.vi.md +63 -0
  63. package/knowledge/ui/composition/accent.md +73 -0
  64. package/knowledge/ui/composition/accent.vi.md +74 -0
  65. package/knowledge/ui/composition/action.md +55 -0
  66. package/knowledge/ui/composition/action.vi.md +56 -0
  67. package/knowledge/ui/composition/coverage.md +37 -0
  68. package/knowledge/ui/composition/coverage.vi.md +37 -0
  69. package/knowledge/ui/composition/cta.md +79 -0
  70. package/knowledge/ui/composition/cta.vi.md +79 -0
  71. package/knowledge/ui/composition/feedback.md +55 -0
  72. package/knowledge/ui/composition/feedback.vi.md +56 -0
  73. package/knowledge/ui/composition/hierarchy.md +83 -0
  74. package/knowledge/ui/composition/hierarchy.vi.md +82 -0
  75. package/knowledge/ui/composition/layout.md +91 -0
  76. package/knowledge/ui/composition/layout.vi.md +93 -0
  77. package/knowledge/ui/composition/responsive.md +67 -0
  78. package/knowledge/ui/composition/responsive.vi.md +67 -0
  79. package/knowledge/ui/composition/state.md +105 -0
  80. package/knowledge/ui/composition/state.vi.md +106 -0
  81. package/knowledge/ui/presentation/INDEX.md +94 -0
  82. package/knowledge/ui/presentation/INDEX.vi.md +69 -0
  83. package/knowledge/ui/presentation/boundary.md +170 -0
  84. package/knowledge/ui/presentation/boundary.vi.md +169 -0
  85. package/knowledge/ui/presentation/font.md +155 -0
  86. package/knowledge/ui/presentation/font.vi.md +156 -0
  87. package/knowledge/ui/presentation/gap.md +181 -0
  88. package/knowledge/ui/presentation/gap.vi.md +181 -0
  89. package/knowledge/ui/presentation/margin.md +168 -0
  90. package/knowledge/ui/presentation/margin.vi.md +171 -0
  91. package/knowledge/ui/presentation/measure.md +174 -0
  92. package/knowledge/ui/presentation/measure.vi.md +178 -0
  93. package/knowledge/ui/presentation/overflow.md +142 -0
  94. package/knowledge/ui/presentation/overflow.vi.md +142 -0
  95. package/knowledge/ui/presentation/padding.md +293 -0
  96. package/knowledge/ui/presentation/padding.vi.md +292 -0
  97. package/knowledge/ui/presentation/surface.md +166 -0
  98. package/knowledge/ui/presentation/surface.vi.md +166 -0
  99. package/knowledge/ui/presentation/text-flow.md +123 -0
  100. package/knowledge/ui/presentation/text-flow.vi.md +123 -0
  101. package/knowledge/ui/presentation/tone.md +114 -0
  102. package/knowledge/ui/presentation/tone.vi.md +113 -0
  103. package/knowledge/ui/proof/INDEX.md +55 -0
  104. package/knowledge/ui/proof/INDEX.vi.md +55 -0
  105. package/knowledge/ui/proof/accessibility.md +67 -0
  106. package/knowledge/ui/proof/accessibility.vi.md +68 -0
  107. package/knowledge/ui/proof/contrast.md +58 -0
  108. package/knowledge/ui/proof/contrast.vi.md +57 -0
  109. package/knowledge/ui/proof/focus.md +76 -0
  110. package/knowledge/ui/proof/focus.vi.md +76 -0
  111. package/knowledge/ui/proof/motion.md +63 -0
  112. package/knowledge/ui/proof/motion.vi.md +64 -0
  113. package/knowledge/ui/proof/render-truth.md +63 -0
  114. package/knowledge/ui/proof/render-truth.vi.md +63 -0
  115. package/operators/INDEX.md +199 -0
  116. package/operators/INDEX.vi.md +199 -0
  117. package/operators/architecture-decide/errors.json +115 -0
  118. package/operators/architecture-decide/operator.json +20 -0
  119. package/operators/architecture-decide/operator.md +133 -0
  120. package/operators/architecture-decide/operator.vi.md +130 -0
  121. package/operators/architecture-decide/self-test.mjs +221 -0
  122. package/operators/architecture-decide/validate.mjs +112 -0
  123. package/operators/backend-source-apply/errors.json +66 -0
  124. package/operators/backend-source-apply/operator.json +20 -0
  125. package/operators/backend-source-apply/operator.md +189 -0
  126. package/operators/backend-source-apply/operator.vi.md +185 -0
  127. package/operators/backend-source-apply/self-test.mjs +257 -0
  128. package/operators/backend-source-apply/validate.mjs +240 -0
  129. package/operators/business-decide/errors.json +78 -0
  130. package/operators/business-decide/operator.json +20 -0
  131. package/operators/business-decide/operator.md +176 -0
  132. package/operators/business-decide/operator.vi.md +174 -0
  133. package/operators/business-decide/self-test.mjs +225 -0
  134. package/operators/business-decide/validate.mjs +277 -0
  135. package/operators/content-generate/errors.json +106 -0
  136. package/operators/content-generate/operator.json +21 -0
  137. package/operators/content-generate/operator.md +155 -0
  138. package/operators/content-generate/operator.vi.md +155 -0
  139. package/operators/content-generate/self-test.mjs +288 -0
  140. package/operators/content-generate/validate.mjs +196 -0
  141. package/operators/errors.json +178 -0
  142. package/operators/frontend-direction-decide/errors.json +135 -0
  143. package/operators/frontend-direction-decide/operator.json +21 -0
  144. package/operators/frontend-direction-decide/operator.md +167 -0
  145. package/operators/frontend-direction-decide/operator.vi.md +167 -0
  146. package/operators/frontend-direction-decide/self-test.mjs +226 -0
  147. package/operators/frontend-direction-decide/validate.mjs +146 -0
  148. package/operators/frontend-presentation-resolve/errors.json +42 -0
  149. package/operators/frontend-presentation-resolve/operator.json +19 -0
  150. package/operators/frontend-presentation-resolve/operator.md +142 -0
  151. package/operators/frontend-presentation-resolve/operator.vi.md +140 -0
  152. package/operators/frontend-presentation-resolve/self-test.mjs +163 -0
  153. package/operators/frontend-presentation-resolve/validate.mjs +143 -0
  154. package/operators/frontend-source-apply/errors.json +30 -0
  155. package/operators/frontend-source-apply/operator.json +20 -0
  156. package/operators/frontend-source-apply/operator.md +127 -0
  157. package/operators/frontend-source-apply/operator.vi.md +126 -0
  158. package/operators/frontend-source-apply/self-test.mjs +214 -0
  159. package/operators/frontend-source-apply/validate.mjs +133 -0
  160. package/operators/frontend-surface-audit/errors.json +5 -0
  161. package/operators/frontend-surface-audit/operator.json +22 -0
  162. package/operators/frontend-surface-audit/operator.md +121 -0
  163. package/operators/frontend-surface-audit/operator.vi.md +121 -0
  164. package/operators/frontend-surface-audit/self-test.mjs +185 -0
  165. package/operators/frontend-surface-audit/validate.mjs +127 -0
  166. package/operators/git-publish/errors.json +54 -0
  167. package/operators/git-publish/operator.json +20 -0
  168. package/operators/git-publish/operator.md +180 -0
  169. package/operators/git-publish/operator.vi.md +178 -0
  170. package/operators/git-publish/self-test.mjs +177 -0
  171. package/operators/git-publish/validate.mjs +106 -0
  172. package/operators/platform-operate/errors.json +90 -0
  173. package/operators/platform-operate/operator.json +22 -0
  174. package/operators/platform-operate/operator.md +162 -0
  175. package/operators/platform-operate/operator.vi.md +160 -0
  176. package/operators/platform-operate/self-test.mjs +202 -0
  177. package/operators/platform-operate/validate.mjs +193 -0
  178. package/operators/quality-verify/errors.json +54 -0
  179. package/operators/quality-verify/operator.json +20 -0
  180. package/operators/quality-verify/operator.md +185 -0
  181. package/operators/quality-verify/operator.vi.md +177 -0
  182. package/operators/quality-verify/self-test.mjs +210 -0
  183. package/operators/quality-verify/validate.mjs +197 -0
  184. package/operators/release-deploy/errors.json +158 -0
  185. package/operators/release-deploy/operator.json +23 -0
  186. package/operators/release-deploy/operator.md +183 -0
  187. package/operators/release-deploy/operator.vi.md +181 -0
  188. package/operators/release-deploy/self-test.mjs +235 -0
  189. package/operators/release-deploy/validate.mjs +129 -0
  190. package/operators/uat-verify/errors.json +78 -0
  191. package/operators/uat-verify/operator.json +25 -0
  192. package/operators/uat-verify/operator.md +162 -0
  193. package/operators/uat-verify/operator.vi.md +161 -0
  194. package/operators/uat-verify/self-test.mjs +270 -0
  195. package/operators/uat-verify/validate.mjs +202 -0
  196. package/operators/workspace-bind/errors.json +90 -0
  197. package/operators/workspace-bind/operator.json +21 -0
  198. package/operators/workspace-bind/operator.md +148 -0
  199. package/operators/workspace-bind/operator.vi.md +148 -0
  200. package/operators/workspace-bind/self-test.mjs +205 -0
  201. package/operators/workspace-bind/validate.mjs +152 -0
  202. package/package.json +50 -0
  203. package/readiness/initialization/workspaces/commit-policy.json +91 -0
  204. package/readiness/initialization/workspaces/config.schema.json +35 -0
  205. package/readiness/initialization/workspaces/device-state.schema.json +54 -0
  206. package/readiness/initialization/workspaces/local-route.schema.json +206 -0
  207. package/readiness/initialization/workspaces/portable-route.schema.json +200 -0
  208. package/resources/INDEX.md +96 -0
  209. package/resources/INDEX.vi.md +99 -0
  210. package/resources/agents/profiles/claude.json +131 -0
  211. package/resources/agents/profiles/openai.json +131 -0
  212. package/resources/orchestrator.json +71 -0
  213. package/resources/tools.json +85 -0
  214. package/routing.json +272 -0
  215. package/scripts/alias-registry.mjs +31 -0
  216. package/scripts/device-state.mjs +497 -0
  217. package/scripts/device-state.spec.mjs +18 -0
  218. package/scripts/errors-registry.mjs +68 -0
  219. package/scripts/generate-alias-doc.mjs +66 -0
  220. package/scripts/generate-grammar-dna.mjs +387 -0
  221. package/scripts/generate-operators-index.mjs +95 -0
  222. package/scripts/generate-presentation-owned.mjs +681 -0
  223. package/scripts/install-cli.spec.mjs +74 -0
  224. package/scripts/json-schema.mjs +94 -0
  225. package/scripts/operator-md.mjs +96 -0
  226. package/scripts/run-operator-self-tests.mjs +36 -0
  227. package/scripts/validate-alias.mjs +165 -0
  228. package/scripts/validate-defaults.mjs +72 -0
  229. package/scripts/validate-knowledge-citations.mjs +90 -0
  230. package/scripts/validate-operator.mjs +125 -0
  231. package/scripts/validate-request.mjs +80 -0
  232. package/scripts/validate-resources.mjs +117 -0
  233. package/scripts/validate-response.mjs +141 -0
  234. package/scripts/validate-routing.mjs +91 -0
  235. package/scripts/validate-step.mjs +50 -0
  236. package/scripts/validate-templates.mjs +226 -0
  237. package/scripts/validate-templates.spec.mjs +144 -0
  238. package/scripts/validate-workflows.mjs +106 -0
  239. package/scripts/workspace-portable.mjs +389 -0
  240. package/scripts/workspace-portable.spec.mjs +246 -0
  241. package/templates/README.md +47 -0
  242. package/templates/README.vi.md +45 -0
  243. package/templates/changes.example.md +27 -0
  244. package/templates/grammars.template.md +34 -0
  245. package/templates/kinds/architecture-decision.contract.json +14 -0
  246. package/templates/kinds/architecture-decision.skeleton.md +52 -0
  247. package/templates/kinds/backend-source-application.contract.json +10 -0
  248. package/templates/kinds/backend-source-application.skeleton.md +34 -0
  249. package/templates/kinds/business-promise-authority.contract.json +13 -0
  250. package/templates/kinds/business-promise-authority.skeleton.md +67 -0
  251. package/templates/kinds/capture.schema.json +33 -0
  252. package/templates/kinds/changes.contract.json +10 -0
  253. package/templates/kinds/changes.skeleton.md +26 -0
  254. package/templates/kinds/checks.schema.json +44 -0
  255. package/templates/kinds/claims.schema.json +165 -0
  256. package/templates/kinds/conformance.schema.json +15 -0
  257. package/templates/kinds/content-brief.contract.json +12 -0
  258. package/templates/kinds/content-brief.skeleton.md +45 -0
  259. package/templates/kinds/content-generation-receipt.contract.json +11 -0
  260. package/templates/kinds/content-generation-receipt.skeleton.md +40 -0
  261. package/templates/kinds/content-review.contract.json +11 -0
  262. package/templates/kinds/content-review.skeleton.md +45 -0
  263. package/templates/kinds/contract.schema.json +28 -0
  264. package/templates/kinds/coverage-matrix.schema.json +86 -0
  265. package/templates/kinds/coverage.schema.json +62 -0
  266. package/templates/kinds/current-state.schema.json +40 -0
  267. package/templates/kinds/delta.schema.json +95 -0
  268. package/templates/kinds/e2e.schema.json +63 -0
  269. package/templates/kinds/frontend-direction-decision.contract.json +93 -0
  270. package/templates/kinds/frontend-direction-decision.skeleton.md +68 -0
  271. package/templates/kinds/frontend-presentation-resolution.contract.json +11 -0
  272. package/templates/kinds/frontend-presentation-resolution.skeleton.md +32 -0
  273. package/templates/kinds/frontend-source-application.contract.json +10 -0
  274. package/templates/kinds/frontend-source-application.skeleton.md +30 -0
  275. package/templates/kinds/frontend-surface-audit.contract.json +52 -0
  276. package/templates/kinds/frontend-surface-audit.skeleton.md +32 -0
  277. package/templates/kinds/gate-result.schema.json +64 -0
  278. package/templates/kinds/git-publication.contract.json +82 -0
  279. package/templates/kinds/git-publication.skeleton.md +61 -0
  280. package/templates/kinds/independent-critique.contract.json +9 -0
  281. package/templates/kinds/independent-critique.skeleton.md +28 -0
  282. package/templates/kinds/inventory.schema.json +35 -0
  283. package/templates/kinds/model.schema.json +99 -0
  284. package/templates/kinds/mutations.schema.json +65 -0
  285. package/templates/kinds/platform-operation-receipt.contract.json +76 -0
  286. package/templates/kinds/platform-operation-receipt.skeleton.md +54 -0
  287. package/templates/kinds/probes.schema.json +130 -0
  288. package/templates/kinds/proof.schema.json +17 -0
  289. package/templates/kinds/quality-verification.contract.json +87 -0
  290. package/templates/kinds/quality-verification.skeleton.md +58 -0
  291. package/templates/kinds/release-deployment.contract.json +85 -0
  292. package/templates/kinds/release-deployment.skeleton.md +67 -0
  293. package/templates/kinds/route.schema.json +293 -0
  294. package/templates/kinds/stack-model.schema.json +90 -0
  295. package/templates/kinds/uat-capture.schema.json +35 -0
  296. package/templates/kinds/uat-flow-verification.contract.json +11 -0
  297. package/templates/kinds/uat-flow-verification.skeleton.md +47 -0
  298. package/templates/kinds/uat-snapshot.schema.json +96 -0
  299. package/templates/kinds/uat-verdicts.schema.json +41 -0
  300. package/templates/kinds/ui-coverage.schema.json +77 -0
  301. package/templates/kinds/verdicts.schema.json +39 -0
  302. package/templates/kinds/workspace-route-binding.contract.json +12 -0
  303. package/templates/kinds/workspace-route-binding.skeleton.md +60 -0
  304. package/templates/kinds/writes.schema.json +37 -0
  305. package/templates/operator.template.md +73 -0
  306. package/templates/patterns.template.md +31 -0
  307. package/templates/step/request.schema.json +42 -0
  308. package/templates/step/response.schema.json +144 -0
  309. package/templates/ui-composition.template.md +36 -0
  310. package/templates/ui-presentation.template.md +57 -0
  311. package/templates/ui-proof.template.md +34 -0
  312. package/workflows/README.md +37 -0
  313. package/workflows/README.vi.md +37 -0
  314. package/workflows/backend-feature.json +59 -0
  315. package/workflows/content-unit.json +19 -0
  316. package/workflows/frontend-new-surface.json +81 -0
  317. package/workflows/frontend-reconstruct.json +67 -0
  318. package/workflows/frontend-refine.json +67 -0
  319. package/workflows/frontend-with-uat.json +78 -0
  320. package/workflows/full-feature.json +104 -0
  321. package/workflows/release.json +29 -0
@@ -0,0 +1,181 @@
1
+ # Gap presentation
2
+
3
+ This file answers one question: given a container the application already decided to render, which
4
+ gap value does it get?
5
+
6
+ Composition has already chosen the DOM tree, the flex or grid direction, and the Grammar objects. Gap
7
+ presentation resolves only the distance between those objects, and only where the application owns
8
+ the container. Distances inside a Grammar object belong to Grammar.
9
+
10
+ ## Scale
11
+
12
+ `COMMON_SPACING_SCALE` is closed. The rule ID is the ordinal position on that scale. It is not the
13
+ Tailwind step number, and the two diverge from GAP-5 onward.
14
+
15
+ | Rule | Class | Value | Common token |
16
+ | --- | --- | --- | --- |
17
+ | GAP-0 | `gap-0` | `0` | none |
18
+ | GAP-1 | `gap-1` | `.25rem` | none |
19
+ | GAP-2 | `gap-2` | `.5rem` | `--grammar-inline-gap` |
20
+ | GAP-3 | `gap-3` | `.75rem` | `--grammar-row-gap` |
21
+ | GAP-4 | `gap-4` | `1rem` | `--grammar-section-gap` |
22
+ | GAP-5 | `gap-6` | `1.5rem` | `--grammar-region-gap` |
23
+ | GAP-6 | `gap-8` | `2rem` | none |
24
+
25
+ The rem values resolve to `0 / 4 / 8 / 12 / 16 / 24 / 32` CSS pixels only at a computed root of
26
+ `16px`. Runtime checks use `expectedPx = remFactor * observedRootFontPx`.
27
+
28
+ ## Owner
29
+
30
+ Each case names who owns the distance. The owner decides whether the application writes a class at
31
+ all.
32
+
33
+ | Owner | Meaning | Application writes |
34
+ | --- | --- | --- |
35
+ | `App` | The container belongs to the application | The class |
36
+ | A component name | Common already applies the gap inside that component | Nothing. Pass the prop |
37
+ | `—` | Common exposes no public path for this relationship | The class, recorded as a workaround |
38
+
39
+ Writing a class where a component is the owner is `APP_REIMPLEMENTATION`. Writing one where the owner
40
+ is `—` stays linked to `COMMON_CAPABILITY_MISSING`.
41
+
42
+ ## Gaps Common already owns
43
+
44
+ Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
45
+
46
+ | Component | Element or condition | Rule |
47
+ | --- | --- | --- |
48
+ | `ChatWorkspace` | layout | GAP-5 |
49
+ | `Divider` | root | GAP-3 |
50
+ | `EmptyNotice` | root | GAP-3 |
51
+ | `Input` | root | GAP-2 |
52
+ | `MediaFrame` | root | GAP-2 |
53
+ | `NavigationFeatureNav` | actions, actions!=undefined | GAP-2 |
54
+ | `NavigationFeatureNav` | primary | GAP-3 |
55
+ | `PrimaryRailLayout` | root | GAP-5 |
56
+ | `Rail` | frame | GAP-4 |
57
+ | `SectionHeader` | copy | GAP-2 |
58
+ | `SectionHeader` | root | GAP-5 |
59
+ | `Sidebar` | list box | GAP-1 |
60
+ | `Sidebar` | list box item, not collapsed | GAP-3 |
61
+ | `Sidebar` | list box section | GAP-1 |
62
+ | `StaticStateRow` | root | GAP-3 |
63
+ | `StaticStateRow` | row copy | GAP-1 |
64
+ | `Subnav` | identity | GAP-2 |
65
+ | `Subnav` | root | GAP-3 |
66
+ | `SurfaceAccordionCard` | label, label!=undefined | GAP-2 |
67
+ | `SurfaceCard` | card content, composition="joined" | GAP-0 |
68
+ | `SurfaceCard` | label, label!=undefined | GAP-2 |
69
+ | `SurfaceCopyGroup` | root, density!="comfortable" | GAP-2 |
70
+ | `SurfaceCopyGroup` | root, density="comfortable" | GAP-3 |
71
+ | `SurfaceListCard` | label, not (label === undefined || labelHidden) | GAP-2 |
72
+ | `Tabs` | tab content | GAP-2 |
73
+ | `Text` | root, not isSkeleton, showsStartContent | GAP-2 |
74
+ | `TextAction` | root | GAP-2 |
75
+ | `WorkspaceShell` | layout | GAP-5 |
76
+ | `WorkspaceShell` | primary | GAP-5 |
77
+
78
+ ## GAP-0 — `gap-0` / `0`
79
+
80
+ Adjacent faces meet with no space because another element already owns the seam.
81
+
82
+ | Case | When | Owner | Render |
83
+ | --- | --- | --- | --- |
84
+ | Case 1 | Stacked bands whose boundary is drawn by a separator | `App` | `<div className="flex flex-col gap-0">` with `<Divider />` between bands |
85
+ | Case 2 | A list whose rows are separated by a border, not by space | `SurfaceListCard` | Compose the card; no gap |
86
+ | Case 3 | Joined faces inside one surface | `SurfaceCard` | `composition="joined"` already sets `0` |
87
+
88
+ ## GAP-1 — `gap-1` / `.25rem`
89
+
90
+ Two stacked lines that read as one identity. The second line qualifies the first rather than
91
+ starting a new item.
92
+
93
+ | Case | When | Owner | Render |
94
+ | --- | --- | --- | --- |
95
+ | Case 1 | A title and the short qualifier bound to it, such as a name under its category | `—` | `<div className="flex flex-col gap-1">` with two `<Text>` |
96
+ | Case 2 | A value and the unit or timestamp bound to it | `—` | Same container |
97
+ | Case 3 | The copy pair inside a status row | `StaticStateRow` | Compose the row; no gap |
98
+
99
+ Not this rule: two separately readable items, even short ones, use GAP-3.
100
+
101
+ ## GAP-2 — `gap-2` / `.5rem`
102
+
103
+ Inline companions inside one control, or two compact items that act as one unit.
104
+
105
+ | Case | When | Owner | Render |
106
+ | --- | --- | --- | --- |
107
+ | Case 1 | An icon beside its label inside one control | `Text` | `<Text startContent={<Icon source={check} />}>Active</Text>` |
108
+ | Case 2 | A title with its explanation inside a surface | `SurfaceCopyGroup` | `<SurfaceCopyGroup>` at default density |
109
+ | Case 3 | Two adjacent inline actions in an app-owned row | `App` | `<div className="flex items-center gap-2">` with two `<TextAction>` |
110
+ | Case 4 | A row of badges or short status chips | `App` | `<div className="flex flex-wrap gap-2">` with `<Badge>` children |
111
+
112
+ ## GAP-3 — `gap-3` / `.75rem`
113
+
114
+ Peer items in one row or one tightly related group. Each item is read on its own, but they belong
115
+ together.
116
+
117
+ | Case | When | Owner | Render |
118
+ | --- | --- | --- | --- |
119
+ | Case 1 | A field and the action that submits it, side by side | `App` | `<div className="flex items-end gap-3">` with `<Input>` and `<Button>` |
120
+ | Case 2 | A title and its explanation that need more air than the compact default | `SurfaceCopyGroup` | `<SurfaceCopyGroup density="comfortable">` |
121
+ | Case 3 | Two peer controls sharing one decision, such as a pair of filters | `App` | `<div className="flex gap-3">` |
122
+ | Case 4 | A section header whose copy and action stack because its container is narrow | `SectionHeader` | Compose the header; no gap |
123
+
124
+ Not this rule: blocks that each carry their own heading use GAP-4.
125
+
126
+ ## GAP-4 — `gap-4` / `1rem`
127
+
128
+ Sibling blocks inside one section. Each block is a separate piece of content, but the section still
129
+ reads as one group.
130
+
131
+ | Case | When | Owner | Render |
132
+ | --- | --- | --- | --- |
133
+ | Case 1 | Stacked content blocks under one section heading | `App` | `<section className="flex flex-col gap-4">` |
134
+ | Case 2 | Cards in a grid belonging to one collection | `App` | `<div className="grid grid-cols-2 gap-4">` with `<SurfaceCard>` children |
135
+ | Case 3 | A form's field groups within one step | `App` | `<div className="flex flex-col gap-4">` with `<Input>` children |
136
+ | Case 4 | Prose blocks inside rendered article content | `MarkdownArticle` | Compose the article; no gap |
137
+
138
+ ## GAP-5 — `gap-6` / `1.5rem`
139
+
140
+ Regions of a page. Each region has its own purpose and its own heading, and the reader moves between
141
+ them rather than through them.
142
+
143
+ | Case | When | Owner | Render |
144
+ | --- | --- | --- | --- |
145
+ | Case 1 | Two page regions with distinct purposes, such as a summary above a history list | `App` | `<main className="flex flex-col gap-6">` with two `<section>` |
146
+ | Case 2 | The standing rhythm between top-level sections of a dashboard | `App` | `<div className="flex flex-col gap-6">` |
147
+ | Case 3 | The primary column beside its rail | `PrimaryRailLayout` | Compose the layout; no gap |
148
+ | Case 4 | Shell regions around routed page content | `WorkspaceShell` | Compose the shell; no gap |
149
+
150
+ Not this rule: blocks that share one heading and one purpose use GAP-4.
151
+
152
+ ## GAP-6 — `gap-8` / `2rem`
153
+
154
+ A named major transition. The strongest break the scale offers, used only when the ordinary region
155
+ rhythm fails to separate two parts of the page.
156
+
157
+ | Case | When | Owner | Render |
158
+ | --- | --- | --- | --- |
159
+ | Case 1 | A page whose halves serve unrelated tasks, where `1.5rem` reads as one continuous column | `—` | `<main className="flex flex-col gap-8">` |
160
+ | Case 2 | A marketing surface whose sections are deliberately spacious | `—` | Same container |
161
+
162
+ Not this rule: applying it to every region uniformly removes hierarchy. Use GAP-5.
163
+
164
+ ## Axis variants
165
+
166
+ `gap-x-*` and `gap-y-*` are not separate rules. They apply an existing rule to one axis when the two
167
+ axes carry different relationships, most often on a wrapping or grid parent.
168
+
169
+ | Axis | Class | Meaning |
170
+ | --- | --- | --- |
171
+ | Inline | `gap-x-*` | The chosen rule applies between columns only |
172
+ | Block | `gap-y-*` | The chosen rule applies between rows only |
173
+
174
+ A wrapping list whose columns are inline companions and whose rows are peers is `gap-x-2 gap-y-3`,
175
+ which is GAP-2 on the inline axis and GAP-3 on the block axis. Each axis names its own case.
176
+
177
+ ## What this file does not decide
178
+
179
+ Padding inside an app boundary is [Padding](padding.md). External offsets are [Margin](margin.md).
180
+ Which DOM structure, flex direction, or Grammar object to render was decided before this file is
181
+ read, and no gap value can repair a wrong composition.
@@ -0,0 +1,181 @@
1
+ # Gap presentation
2
+
3
+ File này trả lời đúng một câu hỏi: một container mà ứng dụng đã quyết định render thì nhận giá trị
4
+ gap nào.
5
+
6
+ Bước composition đã chọn xong cây DOM, hướng flex hay grid, và các Grammar object. Gap presentation
7
+ chỉ giải quyết khoảng cách giữa những object đó, và chỉ ở nơi ứng dụng sở hữu container. Khoảng cách
8
+ bên trong một Grammar object thuộc về Grammar.
9
+
10
+ ## Thang giá trị
11
+
12
+ `COMMON_SPACING_SCALE` là thang đóng. Số của rule là thứ tự trên thang đó. Nó không phải số bậc
13
+ Tailwind, và hai số này lệch nhau từ GAP-5 trở đi.
14
+
15
+ | Rule | Class | Giá trị | Token Common |
16
+ | --- | --- | --- | --- |
17
+ | GAP-0 | `gap-0` | `0` | không có |
18
+ | GAP-1 | `gap-1` | `.25rem` | không có |
19
+ | GAP-2 | `gap-2` | `.5rem` | `--grammar-inline-gap` |
20
+ | GAP-3 | `gap-3` | `.75rem` | `--grammar-row-gap` |
21
+ | GAP-4 | `gap-4` | `1rem` | `--grammar-section-gap` |
22
+ | GAP-5 | `gap-6` | `1.5rem` | `--grammar-region-gap` |
23
+ | GAP-6 | `gap-8` | `2rem` | không có |
24
+
25
+ Các giá trị rem chỉ quy ra `0 / 4 / 8 / 12 / 16 / 24 / 32` pixel CSS khi root font size tính được là
26
+ `16px`. Khi kiểm tra lúc chạy thì dùng `expectedPx = remFactor * observedRootFontPx`.
27
+
28
+ ## Owner
29
+
30
+ Mỗi case gọi tên ai sở hữu khoảng cách. Owner quyết định ứng dụng có được viết class hay không.
31
+
32
+ | Owner | Nghĩa | Ứng dụng viết |
33
+ | --- | --- | --- |
34
+ | `App` | Container thuộc về ứng dụng | Viết class |
35
+ | Tên component | Common đã áp gap bên trong component đó | Không viết gì, chỉ truyền prop |
36
+ | `—` | Common chưa có đường dùng công khai cho quan hệ này | Viết class, ghi nhận là workaround |
37
+
38
+ Viết class ở chỗ owner là một component chính là `APP_REIMPLEMENTATION`. Viết class ở chỗ owner là
39
+ `—` thì gắn liền với `COMMON_CAPABILITY_MISSING`.
40
+
41
+ ## Gap mà Common đã sở hữu
42
+
43
+ Sinh từ claim của `@grammar/core` bằng `scripts/generate-presentation-owned.mjs`; muốn đổi thì sửa component, đừng sửa bảng này.
44
+
45
+ | Component | Phần tử hoặc điều kiện | Rule |
46
+ | --- | --- | --- |
47
+ | `ChatWorkspace` | layout | GAP-5 |
48
+ | `Divider` | root | GAP-3 |
49
+ | `EmptyNotice` | root | GAP-3 |
50
+ | `Input` | root | GAP-2 |
51
+ | `MediaFrame` | root | GAP-2 |
52
+ | `NavigationFeatureNav` | actions, actions!=undefined | GAP-2 |
53
+ | `NavigationFeatureNav` | primary | GAP-3 |
54
+ | `PrimaryRailLayout` | root | GAP-5 |
55
+ | `Rail` | frame | GAP-4 |
56
+ | `SectionHeader` | copy | GAP-2 |
57
+ | `SectionHeader` | root | GAP-5 |
58
+ | `Sidebar` | list box | GAP-1 |
59
+ | `Sidebar` | list box item, not collapsed | GAP-3 |
60
+ | `Sidebar` | list box section | GAP-1 |
61
+ | `StaticStateRow` | root | GAP-3 |
62
+ | `StaticStateRow` | row copy | GAP-1 |
63
+ | `Subnav` | identity | GAP-2 |
64
+ | `Subnav` | root | GAP-3 |
65
+ | `SurfaceAccordionCard` | label, label!=undefined | GAP-2 |
66
+ | `SurfaceCard` | card content, composition="joined" | GAP-0 |
67
+ | `SurfaceCard` | label, label!=undefined | GAP-2 |
68
+ | `SurfaceCopyGroup` | root, density!="comfortable" | GAP-2 |
69
+ | `SurfaceCopyGroup` | root, density="comfortable" | GAP-3 |
70
+ | `SurfaceListCard` | label, not (label === undefined || labelHidden) | GAP-2 |
71
+ | `Tabs` | tab content | GAP-2 |
72
+ | `Text` | root, not isSkeleton, showsStartContent | GAP-2 |
73
+ | `TextAction` | root | GAP-2 |
74
+ | `WorkspaceShell` | layout | GAP-5 |
75
+ | `WorkspaceShell` | primary | GAP-5 |
76
+
77
+ ## GAP-0 — `gap-0` / `0`
78
+
79
+ Hai mặt kề nhau chạm nhau, vì đường ranh đã do một phần tử khác vẽ.
80
+
81
+ | Case | Dùng khi | Owner | Render |
82
+ | --- | --- | --- | --- |
83
+ | Case 1 | Các dải xếp chồng mà ranh giới do separator vẽ | `App` | `<div className="flex flex-col gap-0">` với `<Divider />` giữa các dải |
84
+ | Case 2 | Danh sách mà các hàng cách nhau bằng border chứ không bằng khoảng trắng | `SurfaceListCard` | Ghép card, không viết gap |
85
+ | Case 3 | Các mặt nối liền bên trong một surface | `SurfaceCard` | `composition="joined"` đã đặt sẵn `0` |
86
+
87
+ ## GAP-1 — `gap-1` / `.25rem`
88
+
89
+ Hai dòng xếp dọc đọc lên thành một danh tính. Dòng thứ hai bổ nghĩa cho dòng đầu chứ không mở ra một
90
+ mục mới.
91
+
92
+ | Case | Dùng khi | Owner | Render |
93
+ | --- | --- | --- | --- |
94
+ | Case 1 | Một tiêu đề và dòng phụ ngắn thuộc về nó, kiểu tên nằm dưới nhãn phân loại | `—` | `<div className="flex flex-col gap-1">` với hai `<Text>` |
95
+ | Case 2 | Một giá trị và đơn vị hoặc mốc thời gian dính liền với nó | `—` | Cùng container |
96
+ | Case 3 | Cặp copy bên trong một hàng trạng thái | `StaticStateRow` | Ghép hàng, không viết gap |
97
+
98
+ Không phải rule này: hai mục đọc độc lập được, kể cả khi ngắn, thì dùng GAP-3.
99
+
100
+ ## GAP-2 — `gap-2` / `.5rem`
101
+
102
+ Những thành phần đi kèm nằm trong cùng một control, hoặc hai mục nhỏ hoạt động như một khối.
103
+
104
+ | Case | Dùng khi | Owner | Render |
105
+ | --- | --- | --- | --- |
106
+ | Case 1 | Một icon nằm cạnh label của nó bên trong một control | `Text` | `<Text startContent={<Icon source={check} />}>Active</Text>` |
107
+ | Case 2 | Một tiêu đề và phần giải thích bên trong một surface | `SurfaceCopyGroup` | `<SurfaceCopyGroup>` với density mặc định |
108
+ | Case 3 | Hai inline action đứng cạnh nhau trong hàng do app sở hữu | `App` | `<div className="flex items-center gap-2">` với hai `<TextAction>` |
109
+ | Case 4 | Một hàng badge hoặc chip trạng thái ngắn | `App` | `<div className="flex flex-wrap gap-2">` với các `<Badge>` |
110
+
111
+ ## GAP-3 — `gap-3` / `.75rem`
112
+
113
+ Các mục ngang hàng trong một hàng hoặc một nhóm chặt. Mỗi mục đọc riêng được, nhưng chúng thuộc về
114
+ nhau.
115
+
116
+ | Case | Dùng khi | Owner | Render |
117
+ | --- | --- | --- | --- |
118
+ | Case 1 | Một field và action gửi nó, đặt cạnh nhau | `App` | `<div className="flex items-end gap-3">` với `<Input>` và `<Button>` |
119
+ | Case 2 | Tiêu đề và phần giải thích cần thoáng hơn mức compact mặc định | `SurfaceCopyGroup` | `<SurfaceCopyGroup density="comfortable">` |
120
+ | Case 3 | Hai control ngang hàng phục vụ chung một quyết định, kiểu một cặp bộ lọc | `App` | `<div className="flex gap-3">` |
121
+ | Case 4 | Section header có phần copy và action xếp chồng vì container hẹp | `SectionHeader` | Ghép header, không viết gap |
122
+
123
+ Không phải rule này: các khối mà mỗi khối tự mang tiêu đề riêng thì dùng GAP-4.
124
+
125
+ ## GAP-4 — `gap-4` / `1rem`
126
+
127
+ Các khối ngang hàng trong cùng một section. Mỗi khối là một mảng nội dung riêng, nhưng cả section
128
+ vẫn đọc lên thành một nhóm.
129
+
130
+ | Case | Dùng khi | Owner | Render |
131
+ | --- | --- | --- | --- |
132
+ | Case 1 | Các khối nội dung xếp chồng dưới một tiêu đề section | `App` | `<section className="flex flex-col gap-4">` |
133
+ | Case 2 | Các card trong một lưới cùng thuộc một tập hợp | `App` | `<div className="grid grid-cols-2 gap-4">` với các `<SurfaceCard>` |
134
+ | Case 3 | Các nhóm field của một form trong cùng một bước | `App` | `<div className="flex flex-col gap-4">` với các `<Input>` |
135
+ | Case 4 | Các khối văn bản bên trong nội dung article đã render | `MarkdownArticle` | Ghép article, không viết gap |
136
+
137
+ ## GAP-5 — `gap-6` / `1.5rem`
138
+
139
+ Các vùng của một trang. Mỗi vùng có mục đích riêng và tiêu đề riêng, người đọc nhảy giữa các vùng chứ
140
+ không đọc xuyên qua.
141
+
142
+ | Case | Dùng khi | Owner | Render |
143
+ | --- | --- | --- | --- |
144
+ | Case 1 | Hai vùng trang khác mục đích, kiểu phần tóm tắt nằm trên danh sách lịch sử | `App` | `<main className="flex flex-col gap-6">` với hai `<section>` |
145
+ | Case 2 | Nhịp thường trực giữa các section cấp cao nhất của một dashboard | `App` | `<div className="flex flex-col gap-6">` |
146
+ | Case 3 | Cột chính đặt cạnh rail của nó | `PrimaryRailLayout` | Ghép layout, không viết gap |
147
+ | Case 4 | Các vùng shell bao quanh nội dung trang được route | `WorkspaceShell` | Ghép shell, không viết gap |
148
+
149
+ Không phải rule này: các khối chung một tiêu đề và một mục đích thì dùng GAP-4.
150
+
151
+ ## GAP-6 — `gap-8` / `2rem`
152
+
153
+ Một bước chuyển lớn có tên. Đây là mức ngắt mạnh nhất mà thang cung cấp, chỉ dùng khi nhịp vùng
154
+ thông thường không đủ tách hai phần của trang.
155
+
156
+ | Case | Dùng khi | Owner | Render |
157
+ | --- | --- | --- | --- |
158
+ | Case 1 | Trang mà hai nửa phục vụ hai việc không liên quan, để `1.5rem` thì đọc thành một cột liền mạch | `—` | `<main className="flex flex-col gap-8">` |
159
+ | Case 2 | Một surface marketing mà các section cố ý để thoáng | `—` | Cùng container |
160
+
161
+ Không phải rule này: áp đồng loạt cho mọi vùng thì mất hết phân cấp. Dùng GAP-5.
162
+
163
+ ## Biến thể theo trục
164
+
165
+ `gap-x-*` và `gap-y-*` không phải rule riêng. Chúng áp một rule đã có lên một trục, khi hai trục mang
166
+ hai quan hệ khác nhau, thường gặp trên container wrap hoặc grid.
167
+
168
+ | Trục | Class | Nghĩa |
169
+ | --- | --- | --- |
170
+ | Inline | `gap-x-*` | Rule đã chọn chỉ áp giữa các cột |
171
+ | Block | `gap-y-*` | Rule đã chọn chỉ áp giữa các hàng |
172
+
173
+ Một danh sách wrap mà theo chiều ngang là các thành phần đi kèm còn theo chiều dọc là các mục ngang
174
+ hàng thì viết `gap-x-2 gap-y-3`, tức GAP-2 trên trục inline và GAP-3 trên trục block. Mỗi trục vẫn
175
+ phải gọi tên case của riêng nó.
176
+
177
+ ## File này không quyết định
178
+
179
+ Padding bên trong ranh giới của app thuộc về [Padding](padding.md). Khoảng lệch ra ngoài thuộc về
180
+ [Margin](margin.md). Việc chọn cấu trúc DOM, hướng flex, hay Grammar object nào đã được quyết trước
181
+ khi đọc file này, và không giá trị gap nào cứu được một composition sai.
@@ -0,0 +1,168 @@
1
+ # Margin presentation
2
+
3
+ This file answers one question: when may an application-owned object push away from its surroundings
4
+ with an external offset, and how much?
5
+
6
+ Margin is the exception in this system, not the default. A distance between siblings belongs to the
7
+ parent's gap, and a distance from a boundary to its content belongs to that boundary's padding.
8
+ Margin is correct only when one object needs an offset that no parent relationship can express, and
9
+ that reason has a name.
10
+
11
+ Common reflects this: it resets `margin` to `0` on almost every renderer it owns and lets parents own
12
+ the rhythm. An application that reaches for margin first will produce two owners for one distance,
13
+ which is `DOUBLE_OWNER`.
14
+
15
+ ## Scale
16
+
17
+ `COMMON_SPACING_SCALE` is closed. The rule ID is the ordinal position on that scale. It is not the
18
+ Tailwind step number, and the two diverge from MARGIN-5 onward.
19
+
20
+ | Rule | Class | Value | Common token |
21
+ | --- | --- | --- | --- |
22
+ | MARGIN-0 | `m-0` | `0` | none |
23
+ | MARGIN-1 | `m-1` | `.25rem` | none |
24
+ | MARGIN-2 | `m-2` | `.5rem` | none |
25
+ | MARGIN-3 | `m-3` | `.75rem` | none |
26
+ | MARGIN-4 | `m-4` | `1rem` | none |
27
+ | MARGIN-5 | `m-6` | `1.5rem` | none |
28
+ | MARGIN-6 | `m-8` | `2rem` | none |
29
+
30
+ Common publishes no margin token. `MARGIN-AUTO` is separate and carries no scale value.
31
+
32
+ The rem values resolve to `0 / 4 / 8 / 12 / 16 / 24 / 32` CSS pixels only at a computed root of
33
+ `16px`. Runtime checks use `expectedPx = remFactor * observedRootFontPx`.
34
+
35
+ ## Owner
36
+
37
+ Each case names who owns the offset. The owner decides whether the application writes a class at all.
38
+
39
+ | Owner | Meaning | Application writes |
40
+ | --- | --- | --- |
41
+ | `App` | The offset is a named application placement exception | The class |
42
+ | A component name | Common already sets or resets the margin inside that component | Nothing. Compose it |
43
+ | `—` | Common exposes no public path for this relationship | The class, recorded as a workaround |
44
+
45
+ Writing a class where a component is the owner is `APP_REIMPLEMENTATION`. Adding a child margin next
46
+ to a parent gap that already expresses the same distance is `DOUBLE_OWNER`.
47
+
48
+ ## Margin Common already owns
49
+
50
+ Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
51
+
52
+ | Component | Element or condition | Rule |
53
+ | --- | --- | --- |
54
+ | `Label` | root | MARGIN-0 |
55
+ | `MediaFrame` | root | MARGIN-0 |
56
+ | `PageContainer` | root | MARGIN-AUTO |
57
+ | `SectionHeader` | title | MARGIN-0 |
58
+ | `SurfaceAccordionCard` | accordion trigger wrapper | MARGIN-0 |
59
+ | `WorkspaceShell` | header, hasHeader | MARGIN-5 |
60
+
61
+ ## MARGIN-0 — `m-0` / `0`
62
+
63
+ The offset is removed so a parent relationship becomes the single owner of the distance.
64
+
65
+ | Case | When | Owner | Render |
66
+ | --- | --- | --- | --- |
67
+ | Case 1 | A native element brings a default margin that fights the composition | `App` | `<h2 className="m-0">` inside an app section that owns its gap |
68
+ | Case 2 | Rendered article content whose rhythm is owned by the article | `MarkdownArticle` | Compose the article; no margin |
69
+ | Case 3 | Any Common renderer that already resets its own margin | The component | Compose it; no margin |
70
+
71
+ Not this rule: erasing a deliberate offset without moving that decision to a real owner leaves the
72
+ relationship unowned.
73
+
74
+ ## MARGIN-1 — `m-1` / `.25rem`
75
+
76
+ The smallest external clearance, for one precisely placed object that must sit just clear of an edge.
77
+
78
+ | Case | When | Owner | Render |
79
+ | --- | --- | --- | --- |
80
+ | Case 1 | An absolutely placed marker that would otherwise touch its containing edge | `App` | `<span className="absolute left-0 top-0 m-1">` |
81
+
82
+ Not this rule: repeating it across siblings recreates a gap. Use GAP-1 on the parent.
83
+
84
+ ## MARGIN-2 — `m-2` / `.5rem`
85
+
86
+ A compact offset for one independently placed object.
87
+
88
+ | Case | When | Owner | Render |
89
+ | --- | --- | --- | --- |
90
+ | Case 1 | An overlay caption or control anchored to a corner of an app-owned canvas | `App` | `<aside className="absolute bottom-0 right-0 m-2">` |
91
+
92
+ Not this rule: a substitute for container padding or sibling gap. Use PADDING-2 or GAP-2.
93
+
94
+ ## MARGIN-3 — `m-3` / `.75rem`
95
+
96
+ A dense but noticeable offset for one named placement exception.
97
+
98
+ | Case | When | Owner | Render |
99
+ | --- | --- | --- | --- |
100
+ | Case 1 | A placed object where `.5rem` reads as cramped against a busy background | `App` | `<aside className="absolute right-0 top-0 m-3">` |
101
+
102
+ Not this rule: repeated items in a list. Use GAP-3 on the parent.
103
+
104
+ ## MARGIN-4 — `m-4` / `1rem`
105
+
106
+ The standard external offset for one object with an explicit placement exception.
107
+
108
+ | Case | When | Owner | Render |
109
+ | --- | --- | --- | --- |
110
+ | Case 1 | A standalone object needing equal clearance from an enclosing boundary that cannot own it | `App` | `<aside className="m-4">` |
111
+ | Case 2 | The trailing space after a code block inside article content | `FencedCodeBlock` | Compose the block; no margin |
112
+ | Case 3 | The block rhythm around a horizontal rule in article content | `MarkdownArticle` | Compose the article; no margin |
113
+
114
+ Not this rule: combining it with parent padding for the same edge-to-content purpose produces two
115
+ owners for one distance.
116
+
117
+ ## MARGIN-5 — `m-6` / `1.5rem`
118
+
119
+ A large offset that makes one standalone object visibly detached from its containing boundary.
120
+
121
+ | Case | When | Owner | Render |
122
+ | --- | --- | --- | --- |
123
+ | Case 1 | A named exception that must clear a boundary by more than the standard offset | `App` | `<aside className="m-6">` |
124
+ | Case 2 | The separation below a workspace header | `WorkspaceShell` | Compose the shell; no margin |
125
+
126
+ Not this rule: separation between substantial siblings. Use GAP-5 on the parent.
127
+
128
+ ## MARGIN-6 — `m-8` / `2rem`
129
+
130
+ The largest external clearance, for a deliberately detached object.
131
+
132
+ | Case | When | Owner | Render |
133
+ | --- | --- | --- | --- |
134
+ | Case 1 | One object that must read as separated from everything around it, with a stated reason | `App` | `<aside className="m-8">` |
135
+
136
+ Not this rule: general page rhythm, or repetition across siblings. Use GAP-6 on the parent.
137
+
138
+ ## MARGIN-AUTO — `mx-auto`
139
+
140
+ Auto inline margins divide the free inline space and centre a width-constrained container. It carries
141
+ no scale value and is not an offset decision.
142
+
143
+ | Case | When | Owner | Render |
144
+ | --- | --- | --- | --- |
145
+ | Case 1 | An app-owned container that constrains its own width and must sit centred | `App` | `<main className="mx-auto max-w-3xl">` |
146
+ | Case 2 | A page adopting the packaged measure and inset | `PageContainer` | Compose the container; it already centres |
147
+
148
+ Not this rule: a full-width element, or an attempt to distribute space between siblings. Distribution
149
+ belongs to the parent's layout.
150
+
151
+ ## Axis variants
152
+
153
+ `mx-*` and `my-*` are not separate rules. They apply an existing rule to one axis when only one axis
154
+ carries the exception.
155
+
156
+ | Axis | Class | Meaning |
157
+ | --- | --- | --- |
158
+ | Inline | `mx-*` | The chosen rule applies to logical start and end only |
159
+ | Block | `my-*` | The chosen rule applies to block start and end only |
160
+
161
+ On the same element `m-*` and `mx-*` compete for the inline sides rather than adding. Adjacent block
162
+ margins between siblings collapse, which is a second reason the parent gap is the reliable owner of
163
+ sibling rhythm.
164
+
165
+ ## What this file does not decide
166
+
167
+ Distance between siblings is [Gap](gap.md). The distance from a boundary to its content is
168
+ [Padding](padding.md). Width constraints are [Measure](measure.md).