@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,207 +1,207 @@
1
- # Interaction and states
2
-
3
- Every interactive element has eight states. Most AI-generated UI styles two (default, hover) and forgets the rest. That's where interfaces break.
4
-
5
- ## The eight states
6
-
7
- | State | When | Treatment |
8
- | --- | --- | --- |
9
- | Default | At rest | Base styling |
10
- | Hover | Pointer over (only with `@media (hover: hover)`) | Small shift: colour, 1px translate, subtle border |
11
- | Focus | Keyboard or programmatic focus | Visible ring, `:focus-visible` |
12
- | Active / Pressed | During press | Pressed-in: darker, translate(0 1px) |
13
- | Disabled | Not interactive | Reduced opacity (0.5) + `cursor: not-allowed` + `aria-disabled` |
14
- | Loading | Processing | Inline spinner or progress, label stays readable |
15
- | Error | Failed state | Red border, error icon, message, `aria-invalid` |
16
- | Success | Completed | Green check, confirmation, auto-dismiss |
17
-
18
- If any of these is missing on a production element, the element isn't finished.
19
-
20
- ## Focus rings
21
-
22
- Visible, always, on every interactive element. The default focus ring most browsers give you is fine; a custom one is better.
23
-
24
- ```css
25
- :focus { outline: none; }
26
- :focus-visible {
27
- outline: 2px solid var(--color-focus);
28
- outline-offset: 2px;
29
- border-radius: inherit;
30
- }
31
- ```
32
-
33
- Requirements:
34
-
35
- - 2–3px, ≥ 3:1 contrast against both element and page.
36
- - 2px offset from the element.
37
- - `:focus-visible`, not `:focus`, so it's keyboard-only.
38
- - Never `outline: none` without a replacement. `outline: none` with no other focus style is the most common accessibility bug and an immediate audit failure.
39
-
40
- ## Hit targets
41
-
42
- Minimum 44×44 CSS px for any touch-reachable element. Use padding or an `::before` overlay to expand the hit target without changing visual size:
43
-
44
- ```css
45
- .icon-btn {
46
- position: relative;
47
- }
48
- .icon-btn::before {
49
- content: "";
50
- position: absolute;
51
- inset: -12px;
52
- }
53
- ```
54
-
55
- ## Forms
56
-
57
- - Labels above inputs. Visible. Never placeholder-as-label.
58
- - Placeholders show format, not instruction. `Placeholder: 01 Jan 2026`, not `Placeholder: Enter your birth date`.
59
- - Helper text below input. Error text replaces helper text.
60
- - Validate on **blur**, not on every keystroke. Revalidate on change once the field has been blurred once (the "touched" pattern).
61
- - Error message: (1) what broke, (2) why, (3) what to do. One sentence if possible.
62
- - Associate errors with `aria-describedby`. Set `aria-invalid="true"` on the field.
63
- - Required fields marked with `aria-required`, never with colour alone.
64
- - Disable the submit button only when the form is in a known-invalid or in-flight state. Never on idle.
65
-
66
- ## Input field states — the exhaustive checklist
67
-
68
- This is where the most "almost right" UIs lose. An input field with two states (default + hover) and a different border-width on focus reads as a default settings page — the geometry shifts, the eye notices, the page feels untuned. Every text input, textarea, select, and combobox must satisfy every rule below.
69
-
70
- ### The no-layout-shift rule
71
-
72
- **Border thickness is constant across every state.** Default · hover · focus · error · disabled — the `border-width` value never changes. Layout shift on focus is a tell. State changes go to `background-color`, `outline`, or `box-shadow`, never to `border-width`.
73
-
74
- ```css
75
- .input {
76
- border: 1px solid var(--color-rule-2); /* 1px, always — every state */
77
- outline: 2px solid transparent; /* reserved slot for focus ring; no shift on activate */
78
- outline-offset: 1px;
79
- }
80
- ```
81
-
82
- The outline starts transparent at 2 px so when the focus ring appears, the box geometry is already correct. No layout shift. No paint thrash.
83
-
84
- ### State-by-state recipe
85
-
86
- | State | Treatment | Why |
87
- | --- | --- | --- |
88
- | **Default** | `border: 1px solid var(--color-rule-2)` · `background: var(--color-paper)` · placeholder in `var(--color-muted)` | Visible field, readable empty signal |
89
- | **Hover** | `background: var(--color-paper-2)` (4–6 % darker than paper) · border unchanged | Subtle background shift, no border flash. Border colour changing alone is missable. |
90
- | **Focus** | `outline: 2px solid var(--color-focus)` · `outline-offset: 1px` · border may deepen to `var(--color-ink-2)` but width stays 1 px | Outline is the focus signal; never animated; ≥ 3:1 contrast against page AND field. |
91
- | **Active / typing** | Same as focus. Don't add a separate "typing" state. | Focus already says "active here". A second signal is noise. |
92
- | **Filled** | Same as default — the value carries the state. Optionally a subtle ink-2 border to visually distinguish from empty. | Don't fight the user's content with a styled chrome change. |
93
- | **Disabled** | `opacity: 0.55` · `cursor: not-allowed` · placeholder `var(--color-rule-2)` · `aria-disabled="true"` · `tabindex="-1"` | Three independent signals (opacity + cursor + colour) so no single channel carries the whole load. |
94
- | **Error** | `border-color: var(--color-error, oklch(58% 0.20 25))` · helper-text replaced by error message · `aria-invalid="true"` · small ⚠ glyph at right edge | Border colour flip is OK *because* helper-text and aria signal it too. Never colour alone. |
95
- | **Success** | Subtle accent-coloured border (3 % chroma above default) · small ✓ glyph · auto-clear if user re-edits | Quiet; success doesn't deserve celebration unless it was hard. |
96
- | **Loading** (validating, async) | Inline spinner at the right edge replacing the standard glyph slot · field stays editable but submit disabled | Don't lock the user out of the field. They may want to fix what they typed. |
97
-
98
- ### Heights and rhythm
99
-
100
- - **Input height = button height.** A page with 44 px buttons and 38 px inputs feels untuned. Pick one base height (44 px is the touch-target floor) and apply it to every text input AND every adjacent button.
101
- - **Vertical padding = `(height − line-height-px) / 2`.** No magic numbers.
102
- - **Right-edge slot reserved.** Every input reserves a ~24 px right-edge slot for an optional clear button, error glyph, or loading spinner. If unused, the slot sits empty — never reflow on icon appearance.
103
-
104
- ### Labels, helper, error
105
-
106
- - **Label above** the input, 4–8 px gap. Never inline (placeholder-as-label is a tell).
107
- - **Helper text below**, ~4 px gap. Same `font-size` as the label, lower visual weight.
108
- - **Error replaces helper** — same position, same size, error colour. Never both at once (causes vertical jump on validation).
109
- - **Helper has stable height.** Reserve a 1-line height even when empty, so adding an error doesn't push the page down. CSS: `min-height: 1lh` on the helper container.
110
-
111
- ### Don't, list
112
-
113
- - Don't transition `border-width`, `padding`, or `height` on any state. Always layout-shift.
114
- - Don't transition the focus ring's `opacity` or `transform`. Focus must be instant.
115
- - Don't put hover effects inside `@media (hover: hover)` — wait, *do* put them inside `@media (hover: hover)` so touch users don't get stuck states.
116
- - Don't disable the field as a way to indicate "wait, loading" — use a loading state with the field still editable.
117
- - Don't change `cursor` on `:focus`. The pointer is already a beam; don't fight it.
118
- - Don't use `outline: none` on focus without an explicit replacement.
119
-
120
- ### Specific control overrides
121
-
122
- - **Textarea.** Same rules as input, plus `resize: vertical` (never `none`, never `both` on a small textarea), `min-height: 6rem` for multi-line UX.
123
- - **Select.** Custom-styled `<select>` only if you can replicate native a11y (keyboard, screen-reader). Otherwise leave it native and style the wrapper.
124
- - **Checkbox / radio.** Use `accent-color: var(--color-accent)` for cheap correct styling on modern browsers; only build a custom one when the design requires it. If custom: still a 1 px outline-offset focus ring.
125
- - **Toggle / switch.** It IS a checkbox. Same a11y rules. The visual design doesn't change the contract.
126
- - **Range / slider.** The thumb gets focus state, not the track. Thumb hit-target ≥ 44 px even if visual size is smaller (use a transparent expansion).
127
- - **File input.** Always wrap in a styled label. Native `<input type="file">` is unstyleable; the label is the surface.
128
- - **Combobox / search.** Listbox sits below, `aria-expanded` mirrors visibility, arrow-keys cycle, Enter selects, Escape closes — and the listbox doesn't push page content (use `position: absolute` + a parent `position: relative`).
129
-
130
- ## Modals and overlays
131
-
132
- - Use the native `<dialog>` element. It handles focus trap, escape to close, and `::backdrop` styling for free.
133
- - Set `inert` on the page content behind a modal so tab order doesn't leak.
134
- - Close on: escape key, backdrop click, explicit close button.
135
- - First focus goes to the first interactive element, not the close button.
136
-
137
- ## Dropdowns, tooltips, popovers
138
-
139
- - Use the Popover API (`popover` attribute). It handles light-dismiss, stacking, and escape for free, and works in every modern browser.
140
- - Position with CSS Anchor Positioning where it's available; fall back to `position: fixed` + `getBoundingClientRect()`.
141
- - Never put a dropdown inside an `overflow: hidden` container without escape. It will clip.
142
- - Flip when near the viewport edge.
143
-
144
- ## Undo over confirm
145
-
146
- - For reversible actions, skip the confirm dialog. Do the thing. Show a toast with an Undo button for 5–10 seconds.
147
- - For destructive, irreversible actions (delete account, drop table), keep the confirm — and make the user type the thing being destroyed, not just click "OK".
148
-
149
- ## Loading and empty states
150
-
151
- - **Skeleton** screens over spinners for content that has a predictable shape (lists, cards, tables).
152
- - **Inline spinners** for in-button state. Replace the label, don't add beside it.
153
- - **Empty states** always have: an illustration or icon (a small one), a one-line explanation of why it's empty, an action to fix it.
154
- - Never show a generic "No results" with no context.
155
-
156
- ## Bans
157
-
158
- - Placeholder-as-label.
159
- - Hover-only functionality (touch users can't hover).
160
- - Focus rings removed without replacement.
161
- - Confirmation dialogs for low-stakes actions.
162
- - Touch targets < 44px.
163
- - Custom cursors on interactive elements.
164
- - Disabled elements with no explanation of why they're disabled.
165
- - Colour-only error states.
166
- - Spinners where a skeleton would show layout.
167
-
168
- ---
169
-
170
- ## Contrast discipline
171
-
172
- Hallmark output must pass slop-test gates 46–50 before shipping. Compute contrast for every `(color, background-color)` pair on the page. The common failures Hallmark output trips on:
173
-
174
- 1. **Text on a flipped surface.** `.section--ink { background: var(--color-ink); }` flips the surface dark; nested text still inherits `color: var(--color-ink)` → ink-on-ink. Fix: any rule that sets a dark `background` must *also* set `color: var(--color-paper)` in the same rule.
175
- 2. **Button text on accent fill.** `background: var(--color-accent); color: white;` — but white is 4.5:1 against this accent only if `--color-accent` is dark enough. Use `var(--color-accent-ink)` instead, which the theme guarantees passes ≥ APCA Lc 60.
176
- 3. **Muted text on tinted paper.** `color: var(--color-muted); background: var(--color-paper-3);` — both mid-lightness, often falls below 4.5:1. Use `--color-neutral` (darker) or lift the background to `--color-paper`.
177
- 4. **Focus ring on accent-coloured button.** `outline: 2px solid var(--color-focus);` on a button whose fill is `--color-accent` — if `--color-focus = --color-accent`, the ring vanishes. Use the contrast pair: `--color-focus` set to a colour with ≥ 3:1 against both the element and the page.
178
-
179
- ### Computation
180
-
181
- For each `(text-colour, background-colour)` pair the page actually renders:
182
-
183
- - Run **APCA Lc** (preferred — perceptual) or **WCAG 2.1 ratio**.
184
- - Pre-check: if both are in OKLCH with `|L_a − L_b| < 50 %`, flag for full check.
185
- - Body text passes at **APCA Lc ≥ 60** ≈ WCAG 4.5:1.
186
- - Large text / focus rings / icons pass at **APCA Lc ≥ 45** ≈ WCAG 3:1.
187
-
188
- ### Token contract
189
-
190
- Every theme MUST define `--color-accent-ink` — the text colour to use whenever `--color-accent` fills a surface that carries text. The accent-ink colour is verified ≥ APCA Lc 60 against the accent at the time the theme is built. Hallmark code that uses `background: var(--color-accent)` must also set `color: var(--color-accent-ink)`. Falling back to hardcoded `color: white` is a tell — the theme's accent could be a light colour, and white-on-light is the bug.
191
-
192
- ### When the surface flips
193
-
194
- The rule: **any rule that overrides `background-color` must also state the appropriate `color`.** Don't rely on inheritance for surface-flipping classes. Example:
195
-
196
- ```css
197
- /* WRONG — text inherits color: var(--color-ink); section is now dark; ink-on-ink */
198
- .section--manifesto { background: var(--color-ink); }
199
-
200
- /* RIGHT */
201
- .section--manifesto {
202
- background: var(--color-ink);
203
- color: var(--color-paper);
204
- }
205
- ```
206
-
207
- Same applies to per-theme overrides like `[data-theme="manifesto"] .vs__col:first-child { background: var(--color-ink); }` — set `color: var(--color-paper)` at the same time, OR declare the rule on a parent and let descendants inherit explicitly.
1
+ # Interaction and states
2
+
3
+ Every interactive element has eight states. Most AI-generated UI styles two (default, hover) and forgets the rest. That's where interfaces break.
4
+
5
+ ## The eight states
6
+
7
+ | State | When | Treatment |
8
+ | --- | --- | --- |
9
+ | Default | At rest | Base styling |
10
+ | Hover | Pointer over (only with `@media (hover: hover)`) | Small shift: colour, 1px translate, subtle border |
11
+ | Focus | Keyboard or programmatic focus | Visible ring, `:focus-visible` |
12
+ | Active / Pressed | During press | Pressed-in: darker, translate(0 1px) |
13
+ | Disabled | Not interactive | Reduced opacity (0.5) + `cursor: not-allowed` + `aria-disabled` |
14
+ | Loading | Processing | Inline spinner or progress, label stays readable |
15
+ | Error | Failed state | Red border, error icon, message, `aria-invalid` |
16
+ | Success | Completed | Green check, confirmation, auto-dismiss |
17
+
18
+ If any of these is missing on a production element, the element isn't finished.
19
+
20
+ ## Focus rings
21
+
22
+ Visible, always, on every interactive element. The default focus ring most browsers give you is fine; a custom one is better.
23
+
24
+ ```css
25
+ :focus { outline: none; }
26
+ :focus-visible {
27
+ outline: 2px solid var(--color-focus);
28
+ outline-offset: 2px;
29
+ border-radius: inherit;
30
+ }
31
+ ```
32
+
33
+ Requirements:
34
+
35
+ - 2–3px, ≥ 3:1 contrast against both element and page.
36
+ - 2px offset from the element.
37
+ - `:focus-visible`, not `:focus`, so it's keyboard-only.
38
+ - Never `outline: none` without a replacement. `outline: none` with no other focus style is the most common accessibility bug and an immediate audit failure.
39
+
40
+ ## Hit targets
41
+
42
+ Minimum 44×44 CSS px for any touch-reachable element. Use padding or an `::before` overlay to expand the hit target without changing visual size:
43
+
44
+ ```css
45
+ .icon-btn {
46
+ position: relative;
47
+ }
48
+ .icon-btn::before {
49
+ content: "";
50
+ position: absolute;
51
+ inset: -12px;
52
+ }
53
+ ```
54
+
55
+ ## Forms
56
+
57
+ - Labels above inputs. Visible. Never placeholder-as-label.
58
+ - Placeholders show format, not instruction. `Placeholder: 01 Jan 2026`, not `Placeholder: Enter your birth date`.
59
+ - Helper text below input. Error text replaces helper text.
60
+ - Validate on **blur**, not on every keystroke. Revalidate on change once the field has been blurred once (the "touched" pattern).
61
+ - Error message: (1) what broke, (2) why, (3) what to do. One sentence if possible.
62
+ - Associate errors with `aria-describedby`. Set `aria-invalid="true"` on the field.
63
+ - Required fields marked with `aria-required`, never with colour alone.
64
+ - Disable the submit button only when the form is in a known-invalid or in-flight state. Never on idle.
65
+
66
+ ## Input field states — the exhaustive checklist
67
+
68
+ This is where the most "almost right" UIs lose. An input field with two states (default + hover) and a different border-width on focus reads as a default settings page — the geometry shifts, the eye notices, the page feels untuned. Every text input, textarea, select, and combobox must satisfy every rule below.
69
+
70
+ ### The no-layout-shift rule
71
+
72
+ **Border thickness is constant across every state.** Default · hover · focus · error · disabled — the `border-width` value never changes. Layout shift on focus is a tell. State changes go to `background-color`, `outline`, or `box-shadow`, never to `border-width`.
73
+
74
+ ```css
75
+ .input {
76
+ border: 1px solid var(--color-rule-2); /* 1px, always — every state */
77
+ outline: 2px solid transparent; /* reserved slot for focus ring; no shift on activate */
78
+ outline-offset: 1px;
79
+ }
80
+ ```
81
+
82
+ The outline starts transparent at 2 px so when the focus ring appears, the box geometry is already correct. No layout shift. No paint thrash.
83
+
84
+ ### State-by-state recipe
85
+
86
+ | State | Treatment | Why |
87
+ | --- | --- | --- |
88
+ | **Default** | `border: 1px solid var(--color-rule-2)` · `background: var(--color-paper)` · placeholder in `var(--color-muted)` | Visible field, readable empty signal |
89
+ | **Hover** | `background: var(--color-paper-2)` (4–6 % darker than paper) · border unchanged | Subtle background shift, no border flash. Border colour changing alone is missable. |
90
+ | **Focus** | `outline: 2px solid var(--color-focus)` · `outline-offset: 1px` · border may deepen to `var(--color-ink-2)` but width stays 1 px | Outline is the focus signal; never animated; ≥ 3:1 contrast against page AND field. |
91
+ | **Active / typing** | Same as focus. Don't add a separate "typing" state. | Focus already says "active here". A second signal is noise. |
92
+ | **Filled** | Same as default — the value carries the state. Optionally a subtle ink-2 border to visually distinguish from empty. | Don't fight the user's content with a styled chrome change. |
93
+ | **Disabled** | `opacity: 0.55` · `cursor: not-allowed` · placeholder `var(--color-rule-2)` · `aria-disabled="true"` · `tabindex="-1"` | Three independent signals (opacity + cursor + colour) so no single channel carries the whole load. |
94
+ | **Error** | `border-color: var(--color-error, oklch(58% 0.20 25))` · helper-text replaced by error message · `aria-invalid="true"` · small ⚠ glyph at right edge | Border colour flip is OK *because* helper-text and aria signal it too. Never colour alone. |
95
+ | **Success** | Subtle accent-coloured border (3 % chroma above default) · small ✓ glyph · auto-clear if user re-edits | Quiet; success doesn't deserve celebration unless it was hard. |
96
+ | **Loading** (validating, async) | Inline spinner at the right edge replacing the standard glyph slot · field stays editable but submit disabled | Don't lock the user out of the field. They may want to fix what they typed. |
97
+
98
+ ### Heights and rhythm
99
+
100
+ - **Input height = button height.** A page with 44 px buttons and 38 px inputs feels untuned. Pick one base height (44 px is the touch-target floor) and apply it to every text input AND every adjacent button.
101
+ - **Vertical padding = `(height − line-height-px) / 2`.** No magic numbers.
102
+ - **Right-edge slot reserved.** Every input reserves a ~24 px right-edge slot for an optional clear button, error glyph, or loading spinner. If unused, the slot sits empty — never reflow on icon appearance.
103
+
104
+ ### Labels, helper, error
105
+
106
+ - **Label above** the input, 4–8 px gap. Never inline (placeholder-as-label is a tell).
107
+ - **Helper text below**, ~4 px gap. Same `font-size` as the label, lower visual weight.
108
+ - **Error replaces helper** — same position, same size, error colour. Never both at once (causes vertical jump on validation).
109
+ - **Helper has stable height.** Reserve a 1-line height even when empty, so adding an error doesn't push the page down. CSS: `min-height: 1lh` on the helper container.
110
+
111
+ ### Don't, list
112
+
113
+ - Don't transition `border-width`, `padding`, or `height` on any state. Always layout-shift.
114
+ - Don't transition the focus ring's `opacity` or `transform`. Focus must be instant.
115
+ - Don't put hover effects inside `@media (hover: hover)` — wait, *do* put them inside `@media (hover: hover)` so touch users don't get stuck states.
116
+ - Don't disable the field as a way to indicate "wait, loading" — use a loading state with the field still editable.
117
+ - Don't change `cursor` on `:focus`. The pointer is already a beam; don't fight it.
118
+ - Don't use `outline: none` on focus without an explicit replacement.
119
+
120
+ ### Specific control overrides
121
+
122
+ - **Textarea.** Same rules as input, plus `resize: vertical` (never `none`, never `both` on a small textarea), `min-height: 6rem` for multi-line UX.
123
+ - **Select.** Custom-styled `<select>` only if you can replicate native a11y (keyboard, screen-reader). Otherwise leave it native and style the wrapper.
124
+ - **Checkbox / radio.** Use `accent-color: var(--color-accent)` for cheap correct styling on modern browsers; only build a custom one when the design requires it. If custom: still a 1 px outline-offset focus ring.
125
+ - **Toggle / switch.** It IS a checkbox. Same a11y rules. The visual design doesn't change the contract.
126
+ - **Range / slider.** The thumb gets focus state, not the track. Thumb hit-target ≥ 44 px even if visual size is smaller (use a transparent expansion).
127
+ - **File input.** Always wrap in a styled label. Native `<input type="file">` is unstyleable; the label is the surface.
128
+ - **Combobox / search.** Listbox sits below, `aria-expanded` mirrors visibility, arrow-keys cycle, Enter selects, Escape closes — and the listbox doesn't push page content (use `position: absolute` + a parent `position: relative`).
129
+
130
+ ## Modals and overlays
131
+
132
+ - Use the native `<dialog>` element. It handles focus trap, escape to close, and `::backdrop` styling for free.
133
+ - Set `inert` on the page content behind a modal so tab order doesn't leak.
134
+ - Close on: escape key, backdrop click, explicit close button.
135
+ - First focus goes to the first interactive element, not the close button.
136
+
137
+ ## Dropdowns, tooltips, popovers
138
+
139
+ - Use the Popover API (`popover` attribute). It handles light-dismiss, stacking, and escape for free, and works in every modern browser.
140
+ - Position with CSS Anchor Positioning where it's available; fall back to `position: fixed` + `getBoundingClientRect()`.
141
+ - Never put a dropdown inside an `overflow: hidden` container without escape. It will clip.
142
+ - Flip when near the viewport edge.
143
+
144
+ ## Undo over confirm
145
+
146
+ - For reversible actions, skip the confirm dialog. Do the thing. Show a toast with an Undo button for 5–10 seconds.
147
+ - For destructive, irreversible actions (delete account, drop table), keep the confirm — and make the user type the thing being destroyed, not just click "OK".
148
+
149
+ ## Loading and empty states
150
+
151
+ - **Skeleton** screens over spinners for content that has a predictable shape (lists, cards, tables).
152
+ - **Inline spinners** for in-button state. Replace the label, don't add beside it.
153
+ - **Empty states** always have: an illustration or icon (a small one), a one-line explanation of why it's empty, an action to fix it.
154
+ - Never show a generic "No results" with no context.
155
+
156
+ ## Bans
157
+
158
+ - Placeholder-as-label.
159
+ - Hover-only functionality (touch users can't hover).
160
+ - Focus rings removed without replacement.
161
+ - Confirmation dialogs for low-stakes actions.
162
+ - Touch targets < 44px.
163
+ - Custom cursors on interactive elements.
164
+ - Disabled elements with no explanation of why they're disabled.
165
+ - Colour-only error states.
166
+ - Spinners where a skeleton would show layout.
167
+
168
+ ---
169
+
170
+ ## Contrast discipline
171
+
172
+ Hallmark output must pass slop-test gates 46–50 before shipping. Compute contrast for every `(color, background-color)` pair on the page. The common failures Hallmark output trips on:
173
+
174
+ 1. **Text on a flipped surface.** `.section--ink { background: var(--color-ink); }` flips the surface dark; nested text still inherits `color: var(--color-ink)` → ink-on-ink. Fix: any rule that sets a dark `background` must *also* set `color: var(--color-paper)` in the same rule.
175
+ 2. **Button text on accent fill.** `background: var(--color-accent); color: white;` — but white is 4.5:1 against this accent only if `--color-accent` is dark enough. Use `var(--color-accent-ink)` instead, which the theme guarantees passes ≥ APCA Lc 60.
176
+ 3. **Muted text on tinted paper.** `color: var(--color-muted); background: var(--color-paper-3);` — both mid-lightness, often falls below 4.5:1. Use `--color-neutral` (darker) or lift the background to `--color-paper`.
177
+ 4. **Focus ring on accent-coloured button.** `outline: 2px solid var(--color-focus);` on a button whose fill is `--color-accent` — if `--color-focus = --color-accent`, the ring vanishes. Use the contrast pair: `--color-focus` set to a colour with ≥ 3:1 against both the element and the page.
178
+
179
+ ### Computation
180
+
181
+ For each `(text-colour, background-colour)` pair the page actually renders:
182
+
183
+ - Run **APCA Lc** (preferred — perceptual) or **WCAG 2.1 ratio**.
184
+ - Pre-check: if both are in OKLCH with `|L_a − L_b| < 50 %`, flag for full check.
185
+ - Body text passes at **APCA Lc ≥ 60** ≈ WCAG 4.5:1.
186
+ - Large text / focus rings / icons pass at **APCA Lc ≥ 45** ≈ WCAG 3:1.
187
+
188
+ ### Token contract
189
+
190
+ Every theme MUST define `--color-accent-ink` — the text colour to use whenever `--color-accent` fills a surface that carries text. The accent-ink colour is verified ≥ APCA Lc 60 against the accent at the time the theme is built. Hallmark code that uses `background: var(--color-accent)` must also set `color: var(--color-accent-ink)`. Falling back to hardcoded `color: white` is a tell — the theme's accent could be a light colour, and white-on-light is the bug.
191
+
192
+ ### When the surface flips
193
+
194
+ The rule: **any rule that overrides `background-color` must also state the appropriate `color`.** Don't rely on inheritance for surface-flipping classes. Example:
195
+
196
+ ```css
197
+ /* WRONG — text inherits color: var(--color-ink); section is now dark; ink-on-ink */
198
+ .section--manifesto { background: var(--color-ink); }
199
+
200
+ /* RIGHT */
201
+ .section--manifesto {
202
+ background: var(--color-ink);
203
+ color: var(--color-paper);
204
+ }
205
+ ```
206
+
207
+ Same applies to per-theme overrides like `[data-theme="manifesto"] .vs__col:first-child { background: var(--color-ink); }` — set `color: var(--color-paper)` at the same time, OR declare the rule on a parent and let descendants inherit explicitly.