@phuc1403/musketeer 0.8.0 → 0.10.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 (236) hide show
  1. package/INSTALLATION.md +52 -52
  2. package/README.md +49 -49
  3. package/bin/musketeer.js +168 -168
  4. package/manifest.json +333 -301
  5. package/package.json +48 -48
  6. package/src/dotnet-scaffold-copier.js +79 -79
  7. package/src/provisioner/detect.js +93 -93
  8. package/src/self-update.js +77 -77
  9. package/template/.claude/agents/code-reviewer.md +182 -166
  10. package/template/.claude/agents/git-manager.md +18 -18
  11. package/template/.claude/agents/hallmark-auditor.md +78 -78
  12. package/template/.claude/agents/researcher.md +33 -33
  13. package/template/.claude/hooks/block-unsafe-adr-title.cjs +85 -85
  14. package/template/.claude/hooks/git-skill-reminder.cjs +53 -0
  15. package/template/.claude/hooks/init-adr-dir.cjs +173 -173
  16. package/template/.claude/hooks/inject-adr-flags.cjs +94 -94
  17. package/template/.claude/hooks/lib/adr/command-scan.cjs +115 -115
  18. package/template/.claude/hooks/lib/characteristics/checker.cjs +357 -357
  19. package/template/.claude/hooks/lib/colors.cjs +180 -122
  20. package/template/.claude/hooks/lib/git-info-cache.cjs +191 -191
  21. package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
  22. package/template/.claude/hooks/sync-adr-toc.cjs +146 -146
  23. package/template/.claude/hooks/{usage-context-awareness.cjs → usage-quota-cache-refresh.cjs} +166 -166
  24. package/template/.claude/hooks/validate-characteristics-hook.cjs +66 -66
  25. package/template/.claude/hooks/validate-cml-hook.js +145 -145
  26. package/template/.claude/skills/adr-writer/SKILL.md +48 -48
  27. package/template/.claude/skills/adr-writer/references/adr-example.md +35 -35
  28. package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +215 -215
  29. package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +29 -29
  30. package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +40 -40
  31. package/template/.claude/skills/architecture-characteristic-writer/scripts/ranking-table.cjs +171 -171
  32. package/template/.claude/skills/code-review/SKILL.md +201 -54
  33. package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
  34. package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
  35. package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
  36. package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
  37. package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
  38. package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
  39. package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
  40. package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
  41. package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
  42. package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
  43. package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
  44. package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
  45. package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
  46. package/template/.claude/skills/context-map/SKILL.md +80 -80
  47. package/template/.claude/skills/context-map/example.cml +106 -106
  48. package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +40 -40
  49. package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +5 -5
  50. package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +2 -2
  51. package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +5 -5
  52. package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -1
  53. package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -1
  54. package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +4 -4
  55. package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -9
  56. package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -10
  57. package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -26
  58. package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -23
  59. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -5
  60. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +12 -12
  61. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -5
  62. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +22 -22
  63. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +4 -4
  64. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +13 -13
  65. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +4 -4
  66. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +12 -12
  67. package/template/.claude/skills/context-map/reference/Context Map.md +62 -62
  68. package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -30
  69. package/template/.claude/skills/context-map/reference/Domain/supports.md +33 -33
  70. package/template/.claude/skills/context-map/reference/Domain/type.md +3 -3
  71. package/template/.claude/skills/context-map/reference/Semantic Rules.md +32 -32
  72. package/template/.claude/skills/git/SKILL.md +131 -115
  73. package/template/.claude/skills/git/references/branch-management.md +88 -88
  74. package/template/.claude/skills/git/references/commit-standards.md +46 -46
  75. package/template/.claude/skills/git/references/context-efficiency.md +54 -0
  76. package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
  77. package/template/.claude/skills/git/references/safety-protocols.md +69 -69
  78. package/template/.claude/skills/git/references/workflow-commit.md +58 -58
  79. package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
  80. package/template/.claude/skills/git/references/workflow-merge.md +48 -48
  81. package/template/.claude/skills/git/references/workflow-pr.md +58 -58
  82. package/template/.claude/skills/git/references/workflow-push.md +52 -52
  83. package/template/.claude/skills/hallmark/SKILL.md +552 -552
  84. package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -412
  85. package/template/.claude/skills/hallmark/references/assets.md +406 -406
  86. package/template/.claude/skills/hallmark/references/color.md +95 -95
  87. package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -256
  88. package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -12
  89. package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -16
  90. package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -8
  91. package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -16
  92. package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -20
  93. package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -20
  94. package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -11
  95. package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -11
  96. package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -11
  97. package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -41
  98. package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -13
  99. package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -10
  100. package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -12
  101. package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -10
  102. package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -21
  103. package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -19
  104. package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -27
  105. package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -25
  106. package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -15
  107. package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -15
  108. package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -11
  109. package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -14
  110. package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -11
  111. package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -16
  112. package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -27
  113. package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -23
  114. package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -27
  115. package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -12
  116. package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -19
  117. package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -14
  118. package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -14
  119. package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -9
  120. package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -28
  121. package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -24
  122. package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -22
  123. package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -21
  124. package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -17
  125. package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -15
  126. package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -13
  127. package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -19
  128. package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -11
  129. package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -13
  130. package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -12
  131. package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -19
  132. package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -11
  133. package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -14
  134. package/template/.claude/skills/hallmark/references/contract.md +24 -24
  135. package/template/.claude/skills/hallmark/references/copy.md +182 -182
  136. package/template/.claude/skills/hallmark/references/custom-craft.md +626 -626
  137. package/template/.claude/skills/hallmark/references/custom-theme.md +329 -329
  138. package/template/.claude/skills/hallmark/references/design-md.md +116 -116
  139. package/template/.claude/skills/hallmark/references/export-formats.md +328 -328
  140. package/template/.claude/skills/hallmark/references/floating-nav.md +89 -89
  141. package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -65
  142. package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -70
  143. package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -67
  144. package/template/.claude/skills/hallmark/references/genres/playful.md +65 -65
  145. package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -474
  146. package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -170
  147. package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -207
  148. package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -111
  149. package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -35
  150. package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -34
  151. package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -31
  152. package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -32
  153. package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -32
  154. package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -33
  155. package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -32
  156. package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -34
  157. package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -32
  158. package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -32
  159. package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -23
  160. package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -23
  161. package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -23
  162. package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -23
  163. package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -23
  164. package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -23
  165. package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -23
  166. package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -23
  167. package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -23
  168. package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -23
  169. package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -23
  170. package/template/.claude/skills/hallmark/references/macrostructures.md +89 -89
  171. package/template/.claude/skills/hallmark/references/microinteractions.md +260 -260
  172. package/template/.claude/skills/hallmark/references/motion.md +109 -109
  173. package/template/.claude/skills/hallmark/references/preview-examples.md +49 -49
  174. package/template/.claude/skills/hallmark/references/responsive.md +138 -138
  175. package/template/.claude/skills/hallmark/references/slop-test.md +205 -205
  176. package/template/.claude/skills/hallmark/references/structure.md +164 -164
  177. package/template/.claude/skills/hallmark/references/study.md +511 -511
  178. package/template/.claude/skills/hallmark/references/typography.md +243 -243
  179. package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -25
  180. package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -269
  181. package/template/.claude/skills/hallmark-loop/SKILL.md +105 -105
  182. package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -60
  183. package/template/.claude/skills/hallmark-loop/references/capture.md +78 -78
  184. package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -79
  185. package/template/.claude/skills/handoff/SKILL.md +15 -15
  186. package/template/.claude/skills/knowledge-crunching/SKILL.md +94 -94
  187. package/template/.claude/skills/research/SKILL.md +69 -69
  188. package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
  189. package/template/.claude/skills/skill-creator/SKILL.md +154 -149
  190. package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
  191. package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
  192. package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
  193. package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
  194. package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  195. package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  196. package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
  197. package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
  198. package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
  199. package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
  200. package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
  201. package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
  202. package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
  203. package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
  204. package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
  205. package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
  206. package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
  207. package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
  208. package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
  209. package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
  210. package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
  211. package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
  212. package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
  213. package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
  214. package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
  215. package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
  216. package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
  217. package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
  218. package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
  219. package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  220. package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
  221. package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
  222. package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
  223. package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
  224. package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
  225. package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
  226. package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
  227. package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
  228. package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
  229. package/template/.claude/skills/tdd/SKILL.md +142 -142
  230. package/template/.claude/skills/tdd/deep-modules.md +15 -15
  231. package/template/.claude/skills/tdd/interface-design.md +31 -31
  232. package/template/.claude/skills/tdd/mocking.md +59 -59
  233. package/template/.claude/skills/tdd/refactoring.md +10 -10
  234. package/template/.claude/skills/tdd/tests.md +61 -61
  235. package/template/.claude/statusline.cjs +0 -0
  236. package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
@@ -1,329 +1,329 @@
1
- # Custom theme — protocol
2
-
3
- Loaded only when the user has opted into the **custom** theme route in Step 1 of the Design flow. Custom produces a **complete OKLCH palette + free-font pairing tuned to this brief** — a one-off theme written inline into the page's `:root`, not a permanent catalog entry.
4
-
5
- **The freedom is the combination, not the rules.** Every constraint in [`color.md`](color.md), [`typography.md`](typography.md), and [`anti-patterns.md`](anti-patterns.md) still applies. The 65 slop-test gates fire unchanged. The Step 5 preview block surfaces the palette + pairing in plain text *before* any code is emitted, so the user can redirect.
6
-
7
- ## Two words, plain English
8
-
9
- - **catalog** — the named-theme catalogue. Hallmark's 22 themes (Specimen, Atelier, Brutal, Salon, Newsprint, Linen, Studio, Manifesto, Terminal, Midnight, Almanac, Garden, Quiet, Riso, Sport, Bloom, Coral, Violet, Aurora, Halo, Plume, Editorial). Each one is a fixed combination of paper-band, display-style, and accent-hue. The rotation rule cycles through them so two consecutive runs don't read alike. **This is the default.** Most briefs use it.
10
- - **custom** — made-to-measure. A one-off palette + font pairing constructed specifically for one brief. The skill builds the OKLCH values, picks fonts, and stamps the page — but does **not** extend the catalog with a new theme. The rules behind the catalog (paper L bands, accent chroma caps, font ban list, slop-test gates) all still apply; only the *combination* is per-brief.
11
-
12
- ## When to surface this fork — Step 1 trigger signals
13
-
14
- Hallmark must **not** offer catalog-vs-custom on every prompt. That's friction, not discipline. Surface the fork only when the brief carries one of these signals:
15
-
16
- 1. **Explicit ask** — the user types `custom`, "custom theme", "tailored to our brand", "make it ours", "something unique", "play around with the colors and fonts", "I want my own palette".
17
- 2. **Named brand colour** — the user gives a specific anchor colour as a hex / OKLCH / brand name. Example: "use our terracotta", "the brand red is hex #c0392b", "anchor on sea-blue".
18
- 3. **Multi-attribute aesthetic the catalog can't carry** — three or more vibe words pointing at a specific, off-catalog feel. Examples: "moss, lichen, soft pink, herbal" / "sun-drenched, market-day, carbon-black" / "late-night, neon, brutalist deli". Compare against the 22 catalog themes; if no single catalog theme is within one axis-step of the vibe, fire the fork. **One adjective ("warm", "technical", "playful") is not a signal — that's a tone, the catalog already carries it.**
19
- 4. **Brand-mood reference attached** — the user attaches a colour swatch, a moodboard, a Pantone chip. (If they attach a *page* screenshot, route to `study` instead; custom is for brand colour / mood, study is for design DNA.)
20
-
21
- If any signal fires, ask one short follow-up before picking a theme:
22
-
23
- > *"This brief reads like a custom palette would fit better than the 22 named themes. Want me to construct a custom OKLCH palette + free-font pairing tuned to <one-line summary of the vibe>, or stay on the catalog for variety + speed?"*
24
-
25
- Wait for the user to answer. If they say custom (or yes / go) → continue this protocol from § A. If they say catalog (or no / stay catalog) → drop the fork and proceed with the catalog route. **Default to catalog** — silence routes to catalog, not custom.
26
-
27
- If **none** of the signals fires, do not mention the fork at all. Continue silently with the catalog flow.
28
-
29
- ---
30
-
31
- ## § A · The one follow-up question
32
-
33
- Once the user names `custom` as the theme route, ask **one** thing in **one** message:
34
-
35
- > *"Custom needs one input — describe the brand's vibe in 4–8 words. Examples: 'archival warmth, hand-set, no varnish' · 'industrial precision, cool, technical' · 'moss, lichen, soft pink, herbal' · 'sun-drenched, market-day, carbon black' · 'late-night, neon, brutalist deli'.*
36
- >
37
- > *Optional second input: an anchor colour — hex, OKLCH, or a name like 'terracotta', 'sea-blue', 'forest-green', 'dusty-pink'. If you skip it, I'll pick one from the vibe."*
38
-
39
- **Do not ask anything else.** Audience / use / tone (Step 1) plus the brand vibe is already enough signal. The model has no business asking the user to nominate paper lightness or font weights — that's the model's job.
40
-
41
- If the user gives just two or three words ("sun-drenched"), proceed; the recipe below extracts enough. If the user gives a paragraph, accept it but compress to 4–8 words for the stamp.
42
-
43
- ---
44
-
45
- ## § B · Palette construction
46
-
47
- Build the palette in this order. Each step cites the rule it's obeying — do not restate the rule, just apply it.
48
-
49
- ### B.1 · Anchor accent first
50
-
51
- - Convert the user's named or hex anchor into OKLCH.
52
- - Clamp chroma to **0.12–0.20** per [`color.md`](color.md) § "Accent — the discipline".
53
- - If user skipped: derive hue from the vibe — *warmth* → 30–60° · *technical/industrial* → 220–250° · *botanical/moss* → 130–160° · *late-night/neon* → 280–320° · *sun-drenched/market* → 60–80° amber. Keep chroma 0.12–0.16 (mid-saturation; saturation comes from contrast against neutral, not from chroma).
54
-
55
- ### B.2 · Paper
56
-
57
- - Derive paper L from the vibe:
58
- - bright/airy/breakfast/hand-set → **L 95–98 %** (warm-tinted)
59
- - archival/editorial/restrained → **L 92–95 %** (warm-tinted)
60
- - technical/clinical/spec-sheet → **L 98–100 % near-white** (cool-tinted; can equal #fff but tinted neutrals downstream)
61
- - dark/restless/late-night/manifesto → **L 12–18 %** (anchor-tinted)
62
- - **Always tint paper toward the anchor hue with chroma 0.005–0.020** per [`color.md`](color.md) § "Neutral tinting". Pure-white #fff is allowed only when ink + accent + greys carry the chroma; the paper itself never carries chroma 0 in *both* directions.
63
- - Paper-2 (one elevation step): step ±2–4 % L from paper.
64
- - Paper-3 (optional second step): step ±5–7 % L from paper. Skip on minimal palettes.
65
-
66
- ### B.3 · Ink
67
-
68
- - If paper L < 50: ink L **88–96 %**.
69
- - If paper L ≥ 50: ink L **16–24 %**.
70
- - Tint ink chroma **0.005–0.014** toward anchor (a shade darker / lighter, never neutral).
71
- - Ink-2 (secondary text): step 4–8 % L away from ink toward paper. Same hue family.
72
-
73
- ### B.4 · Supporting greys
74
-
75
- Step by ~6–10 % L between paper and ink, all tinted toward anchor with chroma 0.005–0.018:
76
-
77
- - `--color-rule` — dividers · L ~70–82 % (light paper) or ~26–34 % (dark paper).
78
- - `--color-rule-2` — secondary dividers · 4–6 % L closer to paper than rule.
79
- - `--color-muted` — de-emphasised text · L ~38–56 %.
80
- - `--color-neutral` — mid-grey equivalent · L ~30–56 %.
81
-
82
- These are not arbitrary. The L-step gives the palette **typographic depth** without leaning on accent.
83
-
84
- ### B.5 · Focus
85
-
86
- - Same hue as accent, slightly higher chroma (0.18–0.22) for visibility.
87
- - Same L as accent ±5 %.
88
- - Used only on `:focus-visible` — must show instantly per [`microinteractions.md`](microinteractions.md) § "Focus is a first-class state".
89
-
90
- ### B.6 · Accent-ink (overlay text colour on accent)
91
-
92
- - If accent L > 50: use ink (text reads dark on accent fill).
93
- - If accent L ≤ 50: use paper (text reads light on accent fill).
94
- - Verify **APCA contrast ≥ 7:1** for body, ≥ 3:1 for large text per [`color.md`](color.md).
95
-
96
- ### B.7 · Verification
97
-
98
- - **Gate 8** (no pure #000 / #fff base): paper and ink both have chroma > 0. Pass.
99
- - **Gate 24** (no zero-chroma neutrals): every grey has chroma ≥ 0.005. Pass.
100
- - **Gate 25** (accent ≤ 5 % footprint): plan the accent's role on the page (active state, one wordmark dot, one CTA fill). Don't carpet a section in accent.
101
-
102
- ---
103
-
104
- ## § C · Font pairing
105
-
106
- Custom pulls from the seven tone-pairings in [`typography.md`](typography.md) — Editorial, Technical, Brutalist, Soft, Luxury, Playful, Austere, Workshop. Each tone has a **free baseline** and a **paid upgrade**.
107
-
108
- ### C.1 · The freedom
109
-
110
- The catalog pairs Display-from-tone-X with Body-from-tone-X. **Custom can mix tones** — that's the whole point:
111
-
112
- - Editorial display + Technical body (italic Fraunces wordmark + Geist body) — works for an academic-tone SaaS.
113
- - Brutalist display + Editorial body (Anton + Newsreader italic) — works for a left-leaning manifesto magazine.
114
- - Playful display + Austere body (Bricolage Grotesque + Inter Tight) — works for a creator-tool brand.
115
- - Luxury display + Technical body (Cormorant Garamond + JetBrains Mono) — works for a hand-crafted dev-tool.
116
-
117
- Pick **one display face** and **one body face** from any tone's columns. Optional mono if the page has code or tabular data.
118
-
119
- ### C.2 · The discipline
120
-
121
- - **Free baseline only** unless the user has confirmed paid licences. Per [`typography.md`](typography.md) § "The discipline": "Never name a paid font in code without confirming the user is licensed."
122
- - **Banned defaults still banned** per [`typography.md`](typography.md) § "Banned defaults" — Inter / Roboto / Open Sans / Poppins / Lato / Work Sans / DM Sans / Montserrat / system-ui as display all fail Gate 1.
123
- - **Variable fonts are preferred** when available (Fraunces, Bricolage Grotesque, Newsreader, Geist, EB Garamond, Inter Tight) — they support optical-size and weight axes for tighter typographic control.
124
-
125
- ### C.3 · The pair must read
126
-
127
- Once you have display + body, mentally render the page:
128
-
129
- - Does the display face have enough weight contrast (200/400 next to 700/900) per [`typography.md`](typography.md) § "Commit to extremes"?
130
- - Does the body face read at the chosen body size (≥ 14 px floor; default 1 rem) at the chosen measure (45–75 ch)?
131
- - If display is mono and body is mono — that's only allowed when the page IS the design (Terminal-aesthetic, true single-font specimen). Per [`typography.md`](typography.md) line 7.
132
-
133
- If any answer is no, redirect — pick a different body face or shift the display weight.
134
-
135
- ---
136
-
137
- ## § D · Custom-axis computation
138
-
139
- A custom theme must declare its three diversification-rule axis values explicitly so [`SKILL.md`](../SKILL.md) § "Theme-diversification rule" fires the same way as it does on catalog themes.
140
-
141
- ### D.1 · Paper band
142
-
143
- - **dark** — paper L < 30 %
144
- - **mid** — paper L 30–85 %
145
- - **light** — paper L > 85 %
146
-
147
- ### D.2 · Display style
148
-
149
- Pick one based on the chosen display face:
150
-
151
- - **italic-serif** — Fraunces italic, Newsreader italic, EB Garamond italic, Cormorant italic
152
- - **roman-serif** — Source Serif 4, Newsreader, Crimson Pro, Bitter, Cardo
153
- - **geometric-sans** — Geist, Bricolage Grotesque, Inter Tight, Manrope, Sora
154
- - **mono** — Geist Mono, JetBrains Mono, IBM Plex Mono, Space Mono
155
- - **display-condensed-italic** — Migra italic, Tobias italic
156
- - **display-condensed-bold** — Anton, Bebas Neue, Oswald, Barlow Condensed
157
- - **display-heavy** — Inter Tight 900, Bricolage 800, Druk-class
158
- - **slab-serif** — Roboto Slab, Bitter heavy, Zilla Slab
159
- - **system-native** — system-ui, Inter Tight 400 (austere)
160
- - **risograph-bold** — bold sans with hand-crafted feel
161
- - **handwritten** — Caveat, Sacramento, Patrick Hand (rare; only when brand demands)
162
-
163
- ### D.3 · Accent hue band
164
-
165
- - **warm** — hue 10–60° (red, orange, amber)
166
- - **cool** — hue 200–300° (blue, indigo, cyan)
167
- - **neutral** — no chromatic accent (austere; chroma < 0.05)
168
- - **chromatic-other** — anything outside warm/cool/neutral. Sub-tag the specific anchor: `chromatic-green ~145°` · `chromatic-sage ~120°` · `chromatic-phosphor ~150°` · `chromatic-terracotta ~30°` · `chromatic-dusty-pink ~350°` · `chromatic-moss ~140°` · `chromatic-amber ~75°`.
169
-
170
- ### D.4 · Where these go
171
-
172
- Write all three into the macrostructure stamp (§ E below) and the `.hallmark/log.json` entry (§ F below). They are the durable record. The next run reads them.
173
-
174
- ---
175
-
176
- ## § E · Stamp format
177
-
178
- The CSS comment at the top of the produced stylesheet (per [`SKILL.md`](../SKILL.md) Step 6 § "Stamp the output"):
179
-
180
- ```css
181
- /* Hallmark · macrostructure: <name> · <hero archetype + knobs>
182
- * theme: custom · vibe: "<4–8 words>" · paper: oklch(<L>% <C> <H>) · accent: oklch(<L>% <C> <H>)
183
- * display: <font name> · body: <font name> · axes: <paper-band> / <display-style> / <accent-hue>
184
- * studied: no · context: <user-provided | inferred> · v0.6.x
185
- */
186
- ```
187
-
188
- Concrete example:
189
-
190
- ```css
191
- /* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials
192
- * theme: custom · vibe: "archival warmth, hand-set, no varnish" · paper: oklch(94% 0.020 65) · accent: oklch(58% 0.16 35)
193
- * display: Fraunces italic · body: Source Serif 4 · axes: light / italic-serif / chromatic-terracotta
194
- * studied: no · context: explicit · v0.8.0
195
- */
196
- ```
197
-
198
- The stamp is the durable record. `audit` reads it. The next run reads it. The user reads it.
199
-
200
- ---
201
-
202
- ## § F · `.hallmark/log.json` entry shape
203
-
204
- Custom runs extend the existing schema with a `theme_axes` field and an optional `vibe` field:
205
-
206
- ```json
207
- { "date": "2026-05-01",
208
- "macrostructure": "Stat-Led",
209
- "theme": "custom",
210
- "theme_axes": "light / italic-serif / chromatic-terracotta",
211
- "vibe": "archival warmth, hand-set, no varnish",
212
- "enrichment": "none",
213
- "brief": "Coffeebox · subscription" }
214
- ```
215
-
216
- Catalog entries continue to record `theme: <name>` and skip `theme_axes` (the catalog's axes are looked up from [`tokens.css`](../../../site/css/tokens.css)). Step 2.5 logic uses the same diversification check on both — for catalog entries it reads the axes from tokens.css; for custom entries it reads them from the entry.
217
-
218
- When rotating, **a custom run that follows another custom run must differ on at least one axis from the previous custom** — same rule as catalog-vs-catalog. A custom run that follows a catalog run must differ on at least one axis from the catalog's axes. The diversification rule is theme-route-blind.
219
-
220
- ---
221
-
222
- ## § G · Three worked examples
223
-
224
- Concrete generations to seed model imitation. Each shows the brief, the user's vibe answer, the constructed palette, the chosen pair, and the stamp.
225
-
226
- ### G.1 · Archival café — "Coffeebox"
227
-
228
- **Brief:** *"Build me a landing page for Coffeebox — a small-batch coffee subscription. Roast on Sunday, ship on Monday, drink Tuesday. Audience: people who already buy good coffee and want fewer trips to the shop. Tone: warm, hand-set, editorial — like a small café's chalkboard. Theme route: custom."*
229
-
230
- **Vibe answer:** *"archival warmth, hand-set, no varnish."* **Anchor:** *"terracotta."*
231
-
232
- **Palette:**
233
- - paper `oklch(94% 0.020 65)` — warm-cream, hue 65 (amber-warm)
234
- - paper-2 `oklch(91% 0.022 65)` — one elevation step
235
- - ink `oklch(22% 0.014 60)` — warm dark brown-black
236
- - ink-2 `oklch(40% 0.014 60)` — warm secondary
237
- - rule `oklch(78% 0.018 65)` — warm hairline
238
- - muted `oklch(54% 0.014 60)` — warm grey
239
- - accent `oklch(58% 0.16 35)` — terracotta (hue 35, chroma 0.16)
240
- - accent-ink `oklch(96% 0.014 65)` — paper for text on accent
241
- - focus `oklch(56% 0.20 35)` — accent at higher chroma
242
-
243
- **Pair:** display **Fraunces italic** (Editorial, free) · body **Source Serif 4** (Editorial, free) · mono **JetBrains Mono** (Technical, free).
244
-
245
- **Axes:** **light / italic-serif / chromatic-terracotta**.
246
-
247
- **Stamp:**
248
- ```css
249
- /* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials
250
- * theme: custom · vibe: "archival warmth, hand-set, no varnish" · paper: oklch(94% 0.020 65) · accent: oklch(58% 0.16 35)
251
- * display: Fraunces italic · body: Source Serif 4 · axes: light / italic-serif / chromatic-terracotta
252
- * studied: no · context: explicit · v0.8.0
253
- */
254
- ```
255
-
256
- ### G.2 · Industrial fintech — "Loop"
257
-
258
- **Brief:** *"Loop is a real-time payment-rail observability platform for fintechs. Audience: platform engineers. Use case: try it / contact sales. Tone: industrial, cool, technical. Theme route: custom."*
259
-
260
- **Vibe answer:** *"industrial precision, cool, technical."* **Anchor:** *"sea-blue."*
261
-
262
- **Palette:**
263
- - paper `oklch(13% 0.012 220)` — dark cool
264
- - paper-2 `oklch(17% 0.014 220)` — one step up
265
- - paper-3 `oklch(22% 0.014 220)` — two steps up (panels)
266
- - ink `oklch(94% 0.010 220)` — cool light
267
- - ink-2 `oklch(72% 0.010 220)`
268
- - rule `oklch(30% 0.012 220)`
269
- - muted `oklch(58% 0.012 220)`
270
- - accent `oklch(72% 0.16 220)` — sea-blue (cool)
271
- - focus `oklch(78% 0.20 220)`
272
-
273
- **Pair:** display **Geist Mono 500** (Technical, free) · body **Geist** (Technical, free) · mono **Geist Mono** (Technical, free).
274
-
275
- Note: this *is* a single-family page (Geist + Geist Mono are the same family at different widths). [`typography.md`](typography.md) line 7 allows it: "single-font pages are allowed only when the single font IS the design choice." For an industrial-precision fintech, that's the design choice.
276
-
277
- **Axes:** **dark / mono / cool**.
278
-
279
- **Stamp:**
280
- ```css
281
- /* Hallmark · macrostructure: Workbench · F2 sticky-scroll knobs: pinned=right, content=trace-panel, steps=3
282
- * theme: custom · vibe: "industrial precision, cool, technical" · paper: oklch(13% 0.012 220) · accent: oklch(72% 0.16 220)
283
- * display: Geist Mono 500 · body: Geist · axes: dark / mono / cool
284
- * studied: no · context: explicit · v0.8.0
285
- */
286
- ```
287
-
288
- ### G.3 · Botanical apothecary — "Mossroot"
289
-
290
- **Brief:** *"Mossroot is a small herbal apothecary in Porto. We make tinctures, salves, and tea blends. Audience: locals + visitors. Use: see what we make + visit. Tone: quiet, herbal, hand-poured. Theme route: custom."*
291
-
292
- **Vibe answer:** *"moss, lichen, soft pink, herbal."* **Anchor:** *(skipped — pick from vibe)*.
293
-
294
- The vibe names two hues: *moss* (greenish, ~140°) and *soft pink* (warm, ~350°). Pick **soft pink as the accent** (single anchor — custom is one-accent strict) and use the moss-green as the *paper tint* (chroma 0.018 toward 145°). This carries the dual-vibe without splitting accent.
295
-
296
- **Palette:**
297
- - paper `oklch(96% 0.018 145)` — moss-tinted near-white
298
- - paper-2 `oklch(93% 0.020 145)`
299
- - ink `oklch(22% 0.014 140)` — moss-tinted dark
300
- - ink-2 `oklch(42% 0.014 140)`
301
- - rule `oklch(82% 0.018 145)`
302
- - muted `oklch(56% 0.014 140)`
303
- - accent `oklch(72% 0.13 350)` — dusty-pink (chromatic-other)
304
- - focus `oklch(70% 0.18 350)`
305
-
306
- **Pair:** display **Cormorant Garamond** (Luxury, free) · body **EB Garamond** (Luxury, free) · mono **Geist Mono** (rare on this page; only for ingredient lists).
307
-
308
- **Axes:** **light / roman-serif / chromatic-other (dusty-pink)**.
309
-
310
- **Stamp:**
311
- ```css
312
- /* Hallmark · macrostructure: Catalogue · F1 catalogue knobs: tiles=8, columns=2, rule=hairline-between
313
- * theme: custom · vibe: "moss, lichen, soft pink, herbal" · paper: oklch(96% 0.018 145) · accent: oklch(72% 0.13 350)
314
- * display: Cormorant Garamond · body: EB Garamond · axes: light / roman-serif / chromatic-other (dusty-pink)
315
- * studied: no · context: explicit · v0.8.0
316
- */
317
- ```
318
-
319
- ---
320
-
321
- ## What custom does **not** do (worth restating)
322
-
323
- 1. **Does not invent themes that ignore the rules.** Every paper L band, accent chroma cap, neutral-tinting requirement, font ban, and slop-test gate carries forward. The freedom is the *combination* — not the rules.
324
- 2. **Does not save themes for reuse.** A custom run is per-output. The skill does not write back to [`tokens.css`](../../../site/css/tokens.css). If the user wants a permanent theme, they paste the custom palette into tokens.css themselves and name it.
325
- 3. **Does not ask multiple follow-up questions.** One vibe answer (+ optional anchor) is enough. The audience/use/tone from Step 1 plus the brief plus the macrostructure pick already give the model 80 % of the signal.
326
- 4. **Does not relax the diversification rule.** Custom entries declare their three axes the same way catalog entries do; the rotation rule fires on both, theme-route-blind.
327
- 5. **Does not bypass the Step 5 preview.** The custom palette + pairing surface in plain text *before* any code is emitted, so the user can redirect early.
328
-
329
- If any of those five lines is bent, the custom output is over-invented. Audit it; redirect.
1
+ # Custom theme — protocol
2
+
3
+ Loaded only when the user has opted into the **custom** theme route in Step 1 of the Design flow. Custom produces a **complete OKLCH palette + free-font pairing tuned to this brief** — a one-off theme written inline into the page's `:root`, not a permanent catalog entry.
4
+
5
+ **The freedom is the combination, not the rules.** Every constraint in [`color.md`](color.md), [`typography.md`](typography.md), and [`anti-patterns.md`](anti-patterns.md) still applies. The 65 slop-test gates fire unchanged. The Step 5 preview block surfaces the palette + pairing in plain text *before* any code is emitted, so the user can redirect.
6
+
7
+ ## Two words, plain English
8
+
9
+ - **catalog** — the named-theme catalogue. Hallmark's 22 themes (Specimen, Atelier, Brutal, Salon, Newsprint, Linen, Studio, Manifesto, Terminal, Midnight, Almanac, Garden, Quiet, Riso, Sport, Bloom, Coral, Violet, Aurora, Halo, Plume, Editorial). Each one is a fixed combination of paper-band, display-style, and accent-hue. The rotation rule cycles through them so two consecutive runs don't read alike. **This is the default.** Most briefs use it.
10
+ - **custom** — made-to-measure. A one-off palette + font pairing constructed specifically for one brief. The skill builds the OKLCH values, picks fonts, and stamps the page — but does **not** extend the catalog with a new theme. The rules behind the catalog (paper L bands, accent chroma caps, font ban list, slop-test gates) all still apply; only the *combination* is per-brief.
11
+
12
+ ## When to surface this fork — Step 1 trigger signals
13
+
14
+ Hallmark must **not** offer catalog-vs-custom on every prompt. That's friction, not discipline. Surface the fork only when the brief carries one of these signals:
15
+
16
+ 1. **Explicit ask** — the user types `custom`, "custom theme", "tailored to our brand", "make it ours", "something unique", "play around with the colors and fonts", "I want my own palette".
17
+ 2. **Named brand colour** — the user gives a specific anchor colour as a hex / OKLCH / brand name. Example: "use our terracotta", "the brand red is hex #c0392b", "anchor on sea-blue".
18
+ 3. **Multi-attribute aesthetic the catalog can't carry** — three or more vibe words pointing at a specific, off-catalog feel. Examples: "moss, lichen, soft pink, herbal" / "sun-drenched, market-day, carbon-black" / "late-night, neon, brutalist deli". Compare against the 22 catalog themes; if no single catalog theme is within one axis-step of the vibe, fire the fork. **One adjective ("warm", "technical", "playful") is not a signal — that's a tone, the catalog already carries it.**
19
+ 4. **Brand-mood reference attached** — the user attaches a colour swatch, a moodboard, a Pantone chip. (If they attach a *page* screenshot, route to `study` instead; custom is for brand colour / mood, study is for design DNA.)
20
+
21
+ If any signal fires, ask one short follow-up before picking a theme:
22
+
23
+ > *"This brief reads like a custom palette would fit better than the 22 named themes. Want me to construct a custom OKLCH palette + free-font pairing tuned to <one-line summary of the vibe>, or stay on the catalog for variety + speed?"*
24
+
25
+ Wait for the user to answer. If they say custom (or yes / go) → continue this protocol from § A. If they say catalog (or no / stay catalog) → drop the fork and proceed with the catalog route. **Default to catalog** — silence routes to catalog, not custom.
26
+
27
+ If **none** of the signals fires, do not mention the fork at all. Continue silently with the catalog flow.
28
+
29
+ ---
30
+
31
+ ## § A · The one follow-up question
32
+
33
+ Once the user names `custom` as the theme route, ask **one** thing in **one** message:
34
+
35
+ > *"Custom needs one input — describe the brand's vibe in 4–8 words. Examples: 'archival warmth, hand-set, no varnish' · 'industrial precision, cool, technical' · 'moss, lichen, soft pink, herbal' · 'sun-drenched, market-day, carbon black' · 'late-night, neon, brutalist deli'.*
36
+ >
37
+ > *Optional second input: an anchor colour — hex, OKLCH, or a name like 'terracotta', 'sea-blue', 'forest-green', 'dusty-pink'. If you skip it, I'll pick one from the vibe."*
38
+
39
+ **Do not ask anything else.** Audience / use / tone (Step 1) plus the brand vibe is already enough signal. The model has no business asking the user to nominate paper lightness or font weights — that's the model's job.
40
+
41
+ If the user gives just two or three words ("sun-drenched"), proceed; the recipe below extracts enough. If the user gives a paragraph, accept it but compress to 4–8 words for the stamp.
42
+
43
+ ---
44
+
45
+ ## § B · Palette construction
46
+
47
+ Build the palette in this order. Each step cites the rule it's obeying — do not restate the rule, just apply it.
48
+
49
+ ### B.1 · Anchor accent first
50
+
51
+ - Convert the user's named or hex anchor into OKLCH.
52
+ - Clamp chroma to **0.12–0.20** per [`color.md`](color.md) § "Accent — the discipline".
53
+ - If user skipped: derive hue from the vibe — *warmth* → 30–60° · *technical/industrial* → 220–250° · *botanical/moss* → 130–160° · *late-night/neon* → 280–320° · *sun-drenched/market* → 60–80° amber. Keep chroma 0.12–0.16 (mid-saturation; saturation comes from contrast against neutral, not from chroma).
54
+
55
+ ### B.2 · Paper
56
+
57
+ - Derive paper L from the vibe:
58
+ - bright/airy/breakfast/hand-set → **L 95–98 %** (warm-tinted)
59
+ - archival/editorial/restrained → **L 92–95 %** (warm-tinted)
60
+ - technical/clinical/spec-sheet → **L 98–100 % near-white** (cool-tinted; can equal #fff but tinted neutrals downstream)
61
+ - dark/restless/late-night/manifesto → **L 12–18 %** (anchor-tinted)
62
+ - **Always tint paper toward the anchor hue with chroma 0.005–0.020** per [`color.md`](color.md) § "Neutral tinting". Pure-white #fff is allowed only when ink + accent + greys carry the chroma; the paper itself never carries chroma 0 in *both* directions.
63
+ - Paper-2 (one elevation step): step ±2–4 % L from paper.
64
+ - Paper-3 (optional second step): step ±5–7 % L from paper. Skip on minimal palettes.
65
+
66
+ ### B.3 · Ink
67
+
68
+ - If paper L < 50: ink L **88–96 %**.
69
+ - If paper L ≥ 50: ink L **16–24 %**.
70
+ - Tint ink chroma **0.005–0.014** toward anchor (a shade darker / lighter, never neutral).
71
+ - Ink-2 (secondary text): step 4–8 % L away from ink toward paper. Same hue family.
72
+
73
+ ### B.4 · Supporting greys
74
+
75
+ Step by ~6–10 % L between paper and ink, all tinted toward anchor with chroma 0.005–0.018:
76
+
77
+ - `--color-rule` — dividers · L ~70–82 % (light paper) or ~26–34 % (dark paper).
78
+ - `--color-rule-2` — secondary dividers · 4–6 % L closer to paper than rule.
79
+ - `--color-muted` — de-emphasised text · L ~38–56 %.
80
+ - `--color-neutral` — mid-grey equivalent · L ~30–56 %.
81
+
82
+ These are not arbitrary. The L-step gives the palette **typographic depth** without leaning on accent.
83
+
84
+ ### B.5 · Focus
85
+
86
+ - Same hue as accent, slightly higher chroma (0.18–0.22) for visibility.
87
+ - Same L as accent ±5 %.
88
+ - Used only on `:focus-visible` — must show instantly per [`microinteractions.md`](microinteractions.md) § "Focus is a first-class state".
89
+
90
+ ### B.6 · Accent-ink (overlay text colour on accent)
91
+
92
+ - If accent L > 50: use ink (text reads dark on accent fill).
93
+ - If accent L ≤ 50: use paper (text reads light on accent fill).
94
+ - Verify **APCA contrast ≥ 7:1** for body, ≥ 3:1 for large text per [`color.md`](color.md).
95
+
96
+ ### B.7 · Verification
97
+
98
+ - **Gate 8** (no pure #000 / #fff base): paper and ink both have chroma > 0. Pass.
99
+ - **Gate 24** (no zero-chroma neutrals): every grey has chroma ≥ 0.005. Pass.
100
+ - **Gate 25** (accent ≤ 5 % footprint): plan the accent's role on the page (active state, one wordmark dot, one CTA fill). Don't carpet a section in accent.
101
+
102
+ ---
103
+
104
+ ## § C · Font pairing
105
+
106
+ Custom pulls from the seven tone-pairings in [`typography.md`](typography.md) — Editorial, Technical, Brutalist, Soft, Luxury, Playful, Austere, Workshop. Each tone has a **free baseline** and a **paid upgrade**.
107
+
108
+ ### C.1 · The freedom
109
+
110
+ The catalog pairs Display-from-tone-X with Body-from-tone-X. **Custom can mix tones** — that's the whole point:
111
+
112
+ - Editorial display + Technical body (italic Fraunces wordmark + Geist body) — works for an academic-tone SaaS.
113
+ - Brutalist display + Editorial body (Anton + Newsreader italic) — works for a left-leaning manifesto magazine.
114
+ - Playful display + Austere body (Bricolage Grotesque + Inter Tight) — works for a creator-tool brand.
115
+ - Luxury display + Technical body (Cormorant Garamond + JetBrains Mono) — works for a hand-crafted dev-tool.
116
+
117
+ Pick **one display face** and **one body face** from any tone's columns. Optional mono if the page has code or tabular data.
118
+
119
+ ### C.2 · The discipline
120
+
121
+ - **Free baseline only** unless the user has confirmed paid licences. Per [`typography.md`](typography.md) § "The discipline": "Never name a paid font in code without confirming the user is licensed."
122
+ - **Banned defaults still banned** per [`typography.md`](typography.md) § "Banned defaults" — Inter / Roboto / Open Sans / Poppins / Lato / Work Sans / DM Sans / Montserrat / system-ui as display all fail Gate 1.
123
+ - **Variable fonts are preferred** when available (Fraunces, Bricolage Grotesque, Newsreader, Geist, EB Garamond, Inter Tight) — they support optical-size and weight axes for tighter typographic control.
124
+
125
+ ### C.3 · The pair must read
126
+
127
+ Once you have display + body, mentally render the page:
128
+
129
+ - Does the display face have enough weight contrast (200/400 next to 700/900) per [`typography.md`](typography.md) § "Commit to extremes"?
130
+ - Does the body face read at the chosen body size (≥ 14 px floor; default 1 rem) at the chosen measure (45–75 ch)?
131
+ - If display is mono and body is mono — that's only allowed when the page IS the design (Terminal-aesthetic, true single-font specimen). Per [`typography.md`](typography.md) line 7.
132
+
133
+ If any answer is no, redirect — pick a different body face or shift the display weight.
134
+
135
+ ---
136
+
137
+ ## § D · Custom-axis computation
138
+
139
+ A custom theme must declare its three diversification-rule axis values explicitly so [`SKILL.md`](../SKILL.md) § "Theme-diversification rule" fires the same way as it does on catalog themes.
140
+
141
+ ### D.1 · Paper band
142
+
143
+ - **dark** — paper L < 30 %
144
+ - **mid** — paper L 30–85 %
145
+ - **light** — paper L > 85 %
146
+
147
+ ### D.2 · Display style
148
+
149
+ Pick one based on the chosen display face:
150
+
151
+ - **italic-serif** — Fraunces italic, Newsreader italic, EB Garamond italic, Cormorant italic
152
+ - **roman-serif** — Source Serif 4, Newsreader, Crimson Pro, Bitter, Cardo
153
+ - **geometric-sans** — Geist, Bricolage Grotesque, Inter Tight, Manrope, Sora
154
+ - **mono** — Geist Mono, JetBrains Mono, IBM Plex Mono, Space Mono
155
+ - **display-condensed-italic** — Migra italic, Tobias italic
156
+ - **display-condensed-bold** — Anton, Bebas Neue, Oswald, Barlow Condensed
157
+ - **display-heavy** — Inter Tight 900, Bricolage 800, Druk-class
158
+ - **slab-serif** — Roboto Slab, Bitter heavy, Zilla Slab
159
+ - **system-native** — system-ui, Inter Tight 400 (austere)
160
+ - **risograph-bold** — bold sans with hand-crafted feel
161
+ - **handwritten** — Caveat, Sacramento, Patrick Hand (rare; only when brand demands)
162
+
163
+ ### D.3 · Accent hue band
164
+
165
+ - **warm** — hue 10–60° (red, orange, amber)
166
+ - **cool** — hue 200–300° (blue, indigo, cyan)
167
+ - **neutral** — no chromatic accent (austere; chroma < 0.05)
168
+ - **chromatic-other** — anything outside warm/cool/neutral. Sub-tag the specific anchor: `chromatic-green ~145°` · `chromatic-sage ~120°` · `chromatic-phosphor ~150°` · `chromatic-terracotta ~30°` · `chromatic-dusty-pink ~350°` · `chromatic-moss ~140°` · `chromatic-amber ~75°`.
169
+
170
+ ### D.4 · Where these go
171
+
172
+ Write all three into the macrostructure stamp (§ E below) and the `.hallmark/log.json` entry (§ F below). They are the durable record. The next run reads them.
173
+
174
+ ---
175
+
176
+ ## § E · Stamp format
177
+
178
+ The CSS comment at the top of the produced stylesheet (per [`SKILL.md`](../SKILL.md) Step 6 § "Stamp the output"):
179
+
180
+ ```css
181
+ /* Hallmark · macrostructure: <name> · <hero archetype + knobs>
182
+ * theme: custom · vibe: "<4–8 words>" · paper: oklch(<L>% <C> <H>) · accent: oklch(<L>% <C> <H>)
183
+ * display: <font name> · body: <font name> · axes: <paper-band> / <display-style> / <accent-hue>
184
+ * studied: no · context: <user-provided | inferred> · v0.6.x
185
+ */
186
+ ```
187
+
188
+ Concrete example:
189
+
190
+ ```css
191
+ /* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials
192
+ * theme: custom · vibe: "archival warmth, hand-set, no varnish" · paper: oklch(94% 0.020 65) · accent: oklch(58% 0.16 35)
193
+ * display: Fraunces italic · body: Source Serif 4 · axes: light / italic-serif / chromatic-terracotta
194
+ * studied: no · context: explicit · v0.8.0
195
+ */
196
+ ```
197
+
198
+ The stamp is the durable record. `audit` reads it. The next run reads it. The user reads it.
199
+
200
+ ---
201
+
202
+ ## § F · `.hallmark/log.json` entry shape
203
+
204
+ Custom runs extend the existing schema with a `theme_axes` field and an optional `vibe` field:
205
+
206
+ ```json
207
+ { "date": "2026-05-01",
208
+ "macrostructure": "Stat-Led",
209
+ "theme": "custom",
210
+ "theme_axes": "light / italic-serif / chromatic-terracotta",
211
+ "vibe": "archival warmth, hand-set, no varnish",
212
+ "enrichment": "none",
213
+ "brief": "Coffeebox · subscription" }
214
+ ```
215
+
216
+ Catalog entries continue to record `theme: <name>` and skip `theme_axes` (the catalog's axes are looked up from [`tokens.css`](../../../site/css/tokens.css)). Step 2.5 logic uses the same diversification check on both — for catalog entries it reads the axes from tokens.css; for custom entries it reads them from the entry.
217
+
218
+ When rotating, **a custom run that follows another custom run must differ on at least one axis from the previous custom** — same rule as catalog-vs-catalog. A custom run that follows a catalog run must differ on at least one axis from the catalog's axes. The diversification rule is theme-route-blind.
219
+
220
+ ---
221
+
222
+ ## § G · Three worked examples
223
+
224
+ Concrete generations to seed model imitation. Each shows the brief, the user's vibe answer, the constructed palette, the chosen pair, and the stamp.
225
+
226
+ ### G.1 · Archival café — "Coffeebox"
227
+
228
+ **Brief:** *"Build me a landing page for Coffeebox — a small-batch coffee subscription. Roast on Sunday, ship on Monday, drink Tuesday. Audience: people who already buy good coffee and want fewer trips to the shop. Tone: warm, hand-set, editorial — like a small café's chalkboard. Theme route: custom."*
229
+
230
+ **Vibe answer:** *"archival warmth, hand-set, no varnish."* **Anchor:** *"terracotta."*
231
+
232
+ **Palette:**
233
+ - paper `oklch(94% 0.020 65)` — warm-cream, hue 65 (amber-warm)
234
+ - paper-2 `oklch(91% 0.022 65)` — one elevation step
235
+ - ink `oklch(22% 0.014 60)` — warm dark brown-black
236
+ - ink-2 `oklch(40% 0.014 60)` — warm secondary
237
+ - rule `oklch(78% 0.018 65)` — warm hairline
238
+ - muted `oklch(54% 0.014 60)` — warm grey
239
+ - accent `oklch(58% 0.16 35)` — terracotta (hue 35, chroma 0.16)
240
+ - accent-ink `oklch(96% 0.014 65)` — paper for text on accent
241
+ - focus `oklch(56% 0.20 35)` — accent at higher chroma
242
+
243
+ **Pair:** display **Fraunces italic** (Editorial, free) · body **Source Serif 4** (Editorial, free) · mono **JetBrains Mono** (Technical, free).
244
+
245
+ **Axes:** **light / italic-serif / chromatic-terracotta**.
246
+
247
+ **Stamp:**
248
+ ```css
249
+ /* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials
250
+ * theme: custom · vibe: "archival warmth, hand-set, no varnish" · paper: oklch(94% 0.020 65) · accent: oklch(58% 0.16 35)
251
+ * display: Fraunces italic · body: Source Serif 4 · axes: light / italic-serif / chromatic-terracotta
252
+ * studied: no · context: explicit · v0.8.0
253
+ */
254
+ ```
255
+
256
+ ### G.2 · Industrial fintech — "Loop"
257
+
258
+ **Brief:** *"Loop is a real-time payment-rail observability platform for fintechs. Audience: platform engineers. Use case: try it / contact sales. Tone: industrial, cool, technical. Theme route: custom."*
259
+
260
+ **Vibe answer:** *"industrial precision, cool, technical."* **Anchor:** *"sea-blue."*
261
+
262
+ **Palette:**
263
+ - paper `oklch(13% 0.012 220)` — dark cool
264
+ - paper-2 `oklch(17% 0.014 220)` — one step up
265
+ - paper-3 `oklch(22% 0.014 220)` — two steps up (panels)
266
+ - ink `oklch(94% 0.010 220)` — cool light
267
+ - ink-2 `oklch(72% 0.010 220)`
268
+ - rule `oklch(30% 0.012 220)`
269
+ - muted `oklch(58% 0.012 220)`
270
+ - accent `oklch(72% 0.16 220)` — sea-blue (cool)
271
+ - focus `oklch(78% 0.20 220)`
272
+
273
+ **Pair:** display **Geist Mono 500** (Technical, free) · body **Geist** (Technical, free) · mono **Geist Mono** (Technical, free).
274
+
275
+ Note: this *is* a single-family page (Geist + Geist Mono are the same family at different widths). [`typography.md`](typography.md) line 7 allows it: "single-font pages are allowed only when the single font IS the design choice." For an industrial-precision fintech, that's the design choice.
276
+
277
+ **Axes:** **dark / mono / cool**.
278
+
279
+ **Stamp:**
280
+ ```css
281
+ /* Hallmark · macrostructure: Workbench · F2 sticky-scroll knobs: pinned=right, content=trace-panel, steps=3
282
+ * theme: custom · vibe: "industrial precision, cool, technical" · paper: oklch(13% 0.012 220) · accent: oklch(72% 0.16 220)
283
+ * display: Geist Mono 500 · body: Geist · axes: dark / mono / cool
284
+ * studied: no · context: explicit · v0.8.0
285
+ */
286
+ ```
287
+
288
+ ### G.3 · Botanical apothecary — "Mossroot"
289
+
290
+ **Brief:** *"Mossroot is a small herbal apothecary in Porto. We make tinctures, salves, and tea blends. Audience: locals + visitors. Use: see what we make + visit. Tone: quiet, herbal, hand-poured. Theme route: custom."*
291
+
292
+ **Vibe answer:** *"moss, lichen, soft pink, herbal."* **Anchor:** *(skipped — pick from vibe)*.
293
+
294
+ The vibe names two hues: *moss* (greenish, ~140°) and *soft pink* (warm, ~350°). Pick **soft pink as the accent** (single anchor — custom is one-accent strict) and use the moss-green as the *paper tint* (chroma 0.018 toward 145°). This carries the dual-vibe without splitting accent.
295
+
296
+ **Palette:**
297
+ - paper `oklch(96% 0.018 145)` — moss-tinted near-white
298
+ - paper-2 `oklch(93% 0.020 145)`
299
+ - ink `oklch(22% 0.014 140)` — moss-tinted dark
300
+ - ink-2 `oklch(42% 0.014 140)`
301
+ - rule `oklch(82% 0.018 145)`
302
+ - muted `oklch(56% 0.014 140)`
303
+ - accent `oklch(72% 0.13 350)` — dusty-pink (chromatic-other)
304
+ - focus `oklch(70% 0.18 350)`
305
+
306
+ **Pair:** display **Cormorant Garamond** (Luxury, free) · body **EB Garamond** (Luxury, free) · mono **Geist Mono** (rare on this page; only for ingredient lists).
307
+
308
+ **Axes:** **light / roman-serif / chromatic-other (dusty-pink)**.
309
+
310
+ **Stamp:**
311
+ ```css
312
+ /* Hallmark · macrostructure: Catalogue · F1 catalogue knobs: tiles=8, columns=2, rule=hairline-between
313
+ * theme: custom · vibe: "moss, lichen, soft pink, herbal" · paper: oklch(96% 0.018 145) · accent: oklch(72% 0.13 350)
314
+ * display: Cormorant Garamond · body: EB Garamond · axes: light / roman-serif / chromatic-other (dusty-pink)
315
+ * studied: no · context: explicit · v0.8.0
316
+ */
317
+ ```
318
+
319
+ ---
320
+
321
+ ## What custom does **not** do (worth restating)
322
+
323
+ 1. **Does not invent themes that ignore the rules.** Every paper L band, accent chroma cap, neutral-tinting requirement, font ban, and slop-test gate carries forward. The freedom is the *combination* — not the rules.
324
+ 2. **Does not save themes for reuse.** A custom run is per-output. The skill does not write back to [`tokens.css`](../../../site/css/tokens.css). If the user wants a permanent theme, they paste the custom palette into tokens.css themselves and name it.
325
+ 3. **Does not ask multiple follow-up questions.** One vibe answer (+ optional anchor) is enough. The audience/use/tone from Step 1 plus the brief plus the macrostructure pick already give the model 80 % of the signal.
326
+ 4. **Does not relax the diversification rule.** Custom entries declare their three axes the same way catalog entries do; the rotation rule fires on both, theme-route-blind.
327
+ 5. **Does not bypass the Step 5 preview.** The custom palette + pairing surface in plain text *before* any code is emitted, so the user can redirect early.
328
+
329
+ If any of those five lines is bent, the custom output is over-invented. Audit it; redirect.