@gjermundgaraba-designs/plain-garden 0.0.0-stage → 0.7.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 (209) hide show
  1. package/DESIGN.md +671 -0
  2. package/LICENSE +21 -0
  3. package/README.md +64 -2
  4. package/dist/src/box/box.d.ts +12 -0
  5. package/dist/src/box/box.d.ts.map +1 -0
  6. package/dist/src/box/box.js +4 -0
  7. package/dist/src/box/index.d.ts +3 -0
  8. package/dist/src/box/index.d.ts.map +1 -0
  9. package/dist/src/box/index.js +1 -0
  10. package/dist/src/changes/changes.d.ts +14 -0
  11. package/dist/src/changes/changes.d.ts.map +1 -0
  12. package/dist/src/changes/changes.js +5 -0
  13. package/dist/src/changes/index.d.ts +3 -0
  14. package/dist/src/changes/index.d.ts.map +1 -0
  15. package/dist/src/changes/index.js +1 -0
  16. package/dist/src/codeFigure/codeFigure.d.ts +16 -0
  17. package/dist/src/codeFigure/codeFigure.d.ts.map +1 -0
  18. package/dist/src/codeFigure/codeFigure.js +23 -0
  19. package/dist/src/codeFigure/index.d.ts +3 -0
  20. package/dist/src/codeFigure/index.d.ts.map +1 -0
  21. package/dist/src/codeFigure/index.js +1 -0
  22. package/dist/src/copy/copy.d.ts +83 -0
  23. package/dist/src/copy/copy.d.ts.map +1 -0
  24. package/dist/src/copy/copy.js +76 -0
  25. package/dist/src/copyButton/copyButton.d.ts +40 -0
  26. package/dist/src/copyButton/copyButton.d.ts.map +1 -0
  27. package/dist/src/copyButton/copyButton.js +30 -0
  28. package/dist/src/copyButton/index.d.ts +3 -0
  29. package/dist/src/copyButton/index.d.ts.map +1 -0
  30. package/dist/src/copyButton/index.js +1 -0
  31. package/dist/src/diagram/diagram.d.ts +16 -0
  32. package/dist/src/diagram/diagram.d.ts.map +1 -0
  33. package/dist/src/diagram/diagram.js +15 -0
  34. package/dist/src/diagram/index.d.ts +3 -0
  35. package/dist/src/diagram/index.d.ts.map +1 -0
  36. package/dist/src/diagram/index.js +1 -0
  37. package/dist/src/drawing/drawing.d.ts +22 -0
  38. package/dist/src/drawing/drawing.d.ts.map +1 -0
  39. package/dist/src/drawing/drawing.js +24 -0
  40. package/dist/src/drawing/index.d.ts +4 -0
  41. package/dist/src/drawing/index.d.ts.map +1 -0
  42. package/dist/src/drawing/index.js +1 -0
  43. package/dist/src/drawing/render.d.ts +11 -0
  44. package/dist/src/drawing/render.d.ts.map +1 -0
  45. package/dist/src/drawing/render.js +632 -0
  46. package/dist/src/drawing/scene.d.ts +102 -0
  47. package/dist/src/drawing/scene.d.ts.map +1 -0
  48. package/dist/src/drawing/scene.js +5 -0
  49. package/dist/src/drawnTitle/drawnTitle.d.ts +16 -0
  50. package/dist/src/drawnTitle/drawnTitle.d.ts.map +1 -0
  51. package/dist/src/drawnTitle/drawnTitle.js +14 -0
  52. package/dist/src/drawnTitle/index.d.ts +3 -0
  53. package/dist/src/drawnTitle/index.d.ts.map +1 -0
  54. package/dist/src/drawnTitle/index.js +1 -0
  55. package/dist/src/figRef/figRef.d.ts +8 -0
  56. package/dist/src/figRef/figRef.d.ts.map +1 -0
  57. package/dist/src/figRef/figRef.js +4 -0
  58. package/dist/src/figRef/index.d.ts +3 -0
  59. package/dist/src/figRef/index.d.ts.map +1 -0
  60. package/dist/src/figRef/index.js +1 -0
  61. package/dist/src/figure/figure.d.ts +21 -0
  62. package/dist/src/figure/figure.d.ts.map +1 -0
  63. package/dist/src/figure/figure.js +30 -0
  64. package/dist/src/figure/figures.d.ts +6 -0
  65. package/dist/src/figure/figures.d.ts.map +1 -0
  66. package/dist/src/figure/figures.js +6 -0
  67. package/dist/src/figure/index.d.ts +4 -0
  68. package/dist/src/figure/index.d.ts.map +1 -0
  69. package/dist/src/figure/index.js +2 -0
  70. package/dist/src/illustration/illustration.d.ts +16 -0
  71. package/dist/src/illustration/illustration.d.ts.map +1 -0
  72. package/dist/src/illustration/illustration.js +12 -0
  73. package/dist/src/illustration/index.d.ts +3 -0
  74. package/dist/src/illustration/index.d.ts.map +1 -0
  75. package/dist/src/illustration/index.js +1 -0
  76. package/dist/src/index.d.ts +21 -0
  77. package/dist/src/index.d.ts.map +1 -0
  78. package/dist/src/index.js +20 -0
  79. package/dist/src/linksHere/index.d.ts +3 -0
  80. package/dist/src/linksHere/index.d.ts.map +1 -0
  81. package/dist/src/linksHere/index.js +1 -0
  82. package/dist/src/linksHere/linksHere.d.ts +13 -0
  83. package/dist/src/linksHere/linksHere.d.ts.map +1 -0
  84. package/dist/src/linksHere/linksHere.js +11 -0
  85. package/dist/src/marginNote/index.d.ts +3 -0
  86. package/dist/src/marginNote/index.d.ts.map +1 -0
  87. package/dist/src/marginNote/index.js +1 -0
  88. package/dist/src/marginNote/marginNote.d.ts +13 -0
  89. package/dist/src/marginNote/marginNote.d.ts.map +1 -0
  90. package/dist/src/marginNote/marginNote.js +6 -0
  91. package/dist/src/masthead/index.d.ts +3 -0
  92. package/dist/src/masthead/index.d.ts.map +1 -0
  93. package/dist/src/masthead/index.js +1 -0
  94. package/dist/src/masthead/masthead.d.ts +21 -0
  95. package/dist/src/masthead/masthead.d.ts.map +1 -0
  96. package/dist/src/masthead/masthead.js +23 -0
  97. package/dist/src/noteHeader/index.d.ts +3 -0
  98. package/dist/src/noteHeader/index.d.ts.map +1 -0
  99. package/dist/src/noteHeader/index.js +1 -0
  100. package/dist/src/noteHeader/noteHeader.d.ts +25 -0
  101. package/dist/src/noteHeader/noteHeader.d.ts.map +1 -0
  102. package/dist/src/noteHeader/noteHeader.js +24 -0
  103. package/dist/src/noteList/index.d.ts +3 -0
  104. package/dist/src/noteList/index.d.ts.map +1 -0
  105. package/dist/src/noteList/index.js +1 -0
  106. package/dist/src/noteList/noteList.d.ts +21 -0
  107. package/dist/src/noteList/noteList.d.ts.map +1 -0
  108. package/dist/src/noteList/noteList.js +15 -0
  109. package/dist/src/ring/index.d.ts +3 -0
  110. package/dist/src/ring/index.d.ts.map +1 -0
  111. package/dist/src/ring/index.js +1 -0
  112. package/dist/src/ring/ring.d.ts +13 -0
  113. package/dist/src/ring/ring.d.ts.map +1 -0
  114. package/dist/src/ring/ring.js +20 -0
  115. package/dist/src/scheme/index.d.ts +4 -0
  116. package/dist/src/scheme/index.d.ts.map +1 -0
  117. package/dist/src/scheme/index.js +3 -0
  118. package/dist/src/scheme/scheme.d.ts +10 -0
  119. package/dist/src/scheme/scheme.d.ts.map +1 -0
  120. package/dist/src/scheme/scheme.js +9 -0
  121. package/dist/src/scheme/schemeSwitch.d.ts +17 -0
  122. package/dist/src/scheme/schemeSwitch.d.ts.map +1 -0
  123. package/dist/src/scheme/schemeSwitch.js +18 -0
  124. package/dist/src/scheme/script.d.ts +9 -0
  125. package/dist/src/scheme/script.d.ts.map +1 -0
  126. package/dist/src/scheme/script.js +8 -0
  127. package/dist/src/scheme/switch.d.ts +64 -0
  128. package/dist/src/scheme/switch.d.ts.map +1 -0
  129. package/dist/src/scheme/switch.js +72 -0
  130. package/dist/src/skipLink/index.d.ts +2 -0
  131. package/dist/src/skipLink/index.d.ts.map +1 -0
  132. package/dist/src/skipLink/index.js +1 -0
  133. package/dist/src/skipLink/skipLink.d.ts +8 -0
  134. package/dist/src/skipLink/skipLink.d.ts.map +1 -0
  135. package/dist/src/skipLink/skipLink.js +7 -0
  136. package/dist/src/stage/index.d.ts +3 -0
  137. package/dist/src/stage/index.d.ts.map +1 -0
  138. package/dist/src/stage/index.js +1 -0
  139. package/dist/src/stage/stage.d.ts +13 -0
  140. package/dist/src/stage/stage.d.ts.map +1 -0
  141. package/dist/src/stage/stage.js +23 -0
  142. package/dist/src/summary/index.d.ts +3 -0
  143. package/dist/src/summary/index.d.ts.map +1 -0
  144. package/dist/src/summary/index.js +1 -0
  145. package/dist/src/summary/summary.d.ts +9 -0
  146. package/dist/src/summary/summary.d.ts.map +1 -0
  147. package/dist/src/summary/summary.js +7 -0
  148. package/dist/src/time/time.d.ts +9 -0
  149. package/dist/src/time/time.d.ts.map +1 -0
  150. package/dist/src/time/time.js +9 -0
  151. package/fonts/OFL.txt +386 -0
  152. package/fonts/architects-daughter-latin-400-normal.woff2 +0 -0
  153. package/fonts/atkinson-hyperlegible-mono-latin-wght-italic.woff2 +0 -0
  154. package/fonts/atkinson-hyperlegible-mono-latin-wght-normal.woff2 +0 -0
  155. package/fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2 +0 -0
  156. package/fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2 +0 -0
  157. package/fonts/bricolage-grotesque-latin-wght-normal.woff2 +0 -0
  158. package/package.json +57 -3
  159. package/src/box/box.ts +17 -0
  160. package/src/box/index.ts +2 -0
  161. package/src/changes/changes.ts +22 -0
  162. package/src/changes/index.ts +2 -0
  163. package/src/codeFigure/codeFigure.ts +43 -0
  164. package/src/codeFigure/index.ts +2 -0
  165. package/src/copy/copy.ts +106 -0
  166. package/src/copyButton/copyButton.ts +59 -0
  167. package/src/copyButton/index.ts +12 -0
  168. package/src/diagram/diagram.ts +30 -0
  169. package/src/diagram/index.ts +2 -0
  170. package/src/drawing/drawing.ts +44 -0
  171. package/src/drawing/index.ts +3 -0
  172. package/src/drawing/render.ts +768 -0
  173. package/src/drawing/scene.ts +93 -0
  174. package/src/drawnTitle/drawnTitle.ts +29 -0
  175. package/src/drawnTitle/index.ts +2 -0
  176. package/src/figRef/figRef.ts +12 -0
  177. package/src/figRef/index.ts +2 -0
  178. package/src/figure/figure.ts +66 -0
  179. package/src/figure/figures.ts +7 -0
  180. package/src/figure/index.ts +3 -0
  181. package/src/illustration/illustration.ts +29 -0
  182. package/src/illustration/index.ts +2 -0
  183. package/src/index.ts +20 -0
  184. package/src/linksHere/index.ts +2 -0
  185. package/src/linksHere/linksHere.ts +29 -0
  186. package/src/marginNote/index.ts +2 -0
  187. package/src/marginNote/marginNote.ts +20 -0
  188. package/src/masthead/index.ts +2 -0
  189. package/src/masthead/masthead.ts +46 -0
  190. package/src/noteHeader/index.ts +2 -0
  191. package/src/noteHeader/noteHeader.ts +48 -0
  192. package/src/noteList/index.ts +2 -0
  193. package/src/noteList/noteList.ts +50 -0
  194. package/src/plain-garden.css +1014 -0
  195. package/src/ring/index.ts +2 -0
  196. package/src/ring/ring.ts +39 -0
  197. package/src/scheme/index.ts +3 -0
  198. package/src/scheme/scheme.ts +25 -0
  199. package/src/scheme/schemeSwitch.ts +38 -0
  200. package/src/scheme/script.ts +10 -0
  201. package/src/scheme/switch.ts +99 -0
  202. package/src/skipLink/index.ts +1 -0
  203. package/src/skipLink/skipLink.ts +9 -0
  204. package/src/stage/index.ts +2 -0
  205. package/src/stage/stage.ts +36 -0
  206. package/src/summary/index.ts +2 -0
  207. package/src/summary/summary.ts +14 -0
  208. package/src/time/time.ts +18 -0
  209. package/src/tokens.css +246 -0
package/DESIGN.md ADDED
@@ -0,0 +1,671 @@
1
+ ---
2
+ name: plain-garden
3
+ description: A design system for a personal site kept as a garden; a quiet white reading page whose working drawings show how finished each note is.
4
+ colors:
5
+ paper: "oklch(1 0 0)"
6
+ paper-dark: "oklch(0.18 0.004 265)"
7
+ ink: "oklch(0.21 0.008 265)"
8
+ ink-dark: "oklch(0.96 0.003 265)"
9
+ text: "oklch(0.37 0.01 265)"
10
+ text-dark: "oklch(0.86 0.005 265)"
11
+ ink-soft: "oklch(0.53 0.01 265)"
12
+ ink-soft-dark: "oklch(0.69 0.008 265)"
13
+ rule: "oklch(0.92 0.004 265)"
14
+ rule-dark: "oklch(0.3 0.006 265)"
15
+ wash: "oklch(0.972 0.003 265)"
16
+ wash-dark: "oklch(0.225 0.005 265)"
17
+ accent: "oklch(0.52 0.12 60)"
18
+ accent-dark: "oklch(0.8 0.12 75)"
19
+ mark: "oklch(0.95 0.07 95)"
20
+ mark-dark: "oklch(0.4 0.06 85)"
21
+ selection-bg: "oklch(0.93 0.06 95)"
22
+ selection-bg-dark: "oklch(0.38 0.06 85)"
23
+ draw-line: "oklch(0.44 0.15 260)"
24
+ draw-line-dark: "oklch(0.8 0.1 252)"
25
+ draw-red: "oklch(0.65 0.17 33)"
26
+ draw-red-dark: "oklch(0.76 0.14 32)"
27
+ draw-blue: "oklch(0.62 0.12 248)"
28
+ draw-blue-dark: "oklch(0.76 0.11 245)"
29
+ draw-yellow: "oklch(0.86 0.13 90)"
30
+ draw-yellow-dark: "oklch(0.87 0.13 90)"
31
+ draw-green: "oklch(0.73 0.09 152)"
32
+ draw-green-dark: "oklch(0.8 0.1 152)"
33
+ draw-brown: "oklch(0.67 0.09 62)"
34
+ draw-brown-dark: "oklch(0.77 0.09 62)"
35
+ draw-glass: "oklch(0.92 0.025 240)"
36
+ draw-glass-dark: "oklch(0.64 0.05 240)"
37
+ typography:
38
+ display-greeting:
39
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
40
+ fontSize: "clamp(3.5rem, 7.4vw, 7rem)"
41
+ fontWeight: 800
42
+ lineHeight: 0.88
43
+ letterSpacing: "-0.045em"
44
+ display-note-title:
45
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
46
+ fontSize: "clamp(2.75rem, 5.4vw, 5rem)"
47
+ fontWeight: 800
48
+ lineHeight: 0.88
49
+ letterSpacing: "-0.045em"
50
+ headline:
51
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
52
+ fontSize: "2.25rem"
53
+ fontWeight: 800
54
+ lineHeight: 1.05
55
+ letterSpacing: "-0.03em"
56
+ title:
57
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
58
+ fontSize: "1.75rem"
59
+ fontWeight: 800
60
+ lineHeight: 1.05
61
+ letterSpacing: "-0.03em"
62
+ section:
63
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
64
+ fontSize: "1.25rem"
65
+ fontWeight: 800
66
+ lineHeight: 1.35
67
+ letterSpacing: "-0.03em"
68
+ standfirst:
69
+ fontFamily: '"Bricolage Grotesque", "Atkinson Hyperlegible Next", system-ui, sans-serif'
70
+ fontSize: "1.5rem"
71
+ fontWeight: 500
72
+ lineHeight: 1.3
73
+ letterSpacing: "-0.015em"
74
+ subtitle:
75
+ fontFamily: '"Atkinson Hyperlegible Next", system-ui, sans-serif'
76
+ fontSize: "1.0625rem"
77
+ fontWeight: 700
78
+ lineHeight: 1.7
79
+ body:
80
+ fontFamily: '"Atkinson Hyperlegible Next", system-ui, sans-serif'
81
+ fontSize: "1rem"
82
+ fontWeight: 400
83
+ lineHeight: 1.7
84
+ fontFeature: "kern, liga, calt"
85
+ link:
86
+ fontFamily: '"Atkinson Hyperlegible Next", system-ui, sans-serif'
87
+ fontSize: "1em"
88
+ fontWeight: 500
89
+ small:
90
+ fontFamily: '"Atkinson Hyperlegible Next", system-ui, sans-serif'
91
+ fontSize: "0.9375rem"
92
+ fontWeight: 400
93
+ lineHeight: 1.5
94
+ label:
95
+ fontFamily: '"Atkinson Hyperlegible Next", system-ui, sans-serif'
96
+ fontSize: "0.8125rem"
97
+ fontWeight: 400
98
+ lineHeight: 1.55
99
+ fontFeature: "tnum"
100
+ code-inline:
101
+ fontFamily: '"Atkinson Hyperlegible Mono", ui-monospace, Menlo, Consolas, monospace'
102
+ fontSize: "0.875em"
103
+ fontWeight: 400
104
+ code-block:
105
+ fontFamily: '"Atkinson Hyperlegible Mono", ui-monospace, Menlo, Consolas, monospace'
106
+ fontSize: "0.8125rem"
107
+ fontWeight: 400
108
+ lineHeight: 1.65
109
+ parts:
110
+ fontFamily: '"Atkinson Hyperlegible Mono", ui-monospace, Menlo, Consolas, monospace'
111
+ fontSize: "0.6875rem"
112
+ fontWeight: 500
113
+ letterSpacing: "0.08em"
114
+ drawing-marks:
115
+ fontFamily: '"Atkinson Hyperlegible Mono", ui-monospace, Menlo, Consolas, monospace'
116
+ fontSize: "11px"
117
+ fontWeight: 500
118
+ letterSpacing: "0.08em"
119
+ hand:
120
+ fontFamily: '"Architects Daughter", "Atkinson Hyperlegible Next", system-ui, sans-serif'
121
+ fontSize: "0.9375rem"
122
+ fontWeight: 400
123
+ lineHeight: 1.3
124
+ hand-in-drawing:
125
+ fontFamily: '"Architects Daughter", "Atkinson Hyperlegible Next", system-ui, sans-serif'
126
+ fontSize: "15px"
127
+ fontWeight: 400
128
+ rounded:
129
+ sm: "0.25rem"
130
+ md: "0.375rem"
131
+ spacing:
132
+ u: "0.5rem"
133
+ measure: "34rem"
134
+ page-top: "3.5rem"
135
+ page-left: "clamp(1.25rem, 8vw, 7.5rem)"
136
+ page-right: "1.25rem"
137
+ page-bottom: "5rem"
138
+ mark-col: "1.5rem"
139
+ change-date: "9rem"
140
+ list-indent: "1.5em"
141
+ pre-pad: "1.125rem"
142
+ drawn-width: "75rem"
143
+ margin-note: "15rem"
144
+ margin-reach: "19rem"
145
+ margin-note-narrow: "9rem"
146
+ illustration-small: "10rem"
147
+ components:
148
+ link:
149
+ textColor: "{colors.ink}"
150
+ typography: "{typography.link}"
151
+ link-visited:
152
+ textColor: "{colors.text}"
153
+ skip-link:
154
+ textColor: "{colors.ink}"
155
+ typography: "{typography.label}"
156
+ text-button:
157
+ textColor: "{colors.ink-soft}"
158
+ padding: "0"
159
+ text-button-on:
160
+ textColor: "{colors.ink}"
161
+ flag:
162
+ textColor: "{colors.accent}"
163
+ typography: "{typography.label}"
164
+ note-meta:
165
+ textColor: "{colors.ink-soft}"
166
+ typography: "{typography.label}"
167
+ standfirst:
168
+ textColor: "{colors.ink}"
169
+ typography: "{typography.standfirst}"
170
+ stage-mark:
171
+ textColor: "{colors.ink}"
172
+ size: "0.75rem"
173
+ code-inline:
174
+ backgroundColor: "{colors.wash}"
175
+ textColor: "{colors.ink}"
176
+ rounded: "{rounded.sm}"
177
+ padding: "0.1em 0.3em"
178
+ code-block:
179
+ backgroundColor: "{colors.wash}"
180
+ textColor: "{colors.ink}"
181
+ rounded: "{rounded.md}"
182
+ padding: "0.875rem 1.125rem"
183
+ typography: "{typography.code-block}"
184
+ kbd:
185
+ backgroundColor: "{colors.wash}"
186
+ textColor: "{colors.ink}"
187
+ rounded: "{rounded.sm}"
188
+ padding: "0.1em 0.3em"
189
+ highlight:
190
+ backgroundColor: "{colors.mark}"
191
+ textColor: "{colors.ink}"
192
+ drawn-title:
193
+ width: "75rem"
194
+ typography: "{typography.display-greeting}"
195
+ drawn-title-note:
196
+ typography: "{typography.display-note-title}"
197
+ parts-list:
198
+ textColor: "{colors.draw-line}"
199
+ typography: "{typography.parts}"
200
+ illustration-small:
201
+ width: "10rem"
202
+ margin-note:
203
+ textColor: "{colors.draw-line}"
204
+ typography: "{typography.hand}"
205
+ width: "15rem"
206
+ margin-note-narrow:
207
+ width: "9rem"
208
+ ---
209
+
210
+ # Design System: plain-garden
211
+
212
+ ## Overview
213
+
214
+ **Creative North Star: "Drafted garden"**
215
+
216
+ A personal site kept rather than published, set as a quiet white reading page: one column hung from the left, the open space to its right kept for the writer's drawings. The words are calm (Atkinson Hyperlegible Next, ink links a step heavier than the text, hairlines for every division). The drawings carry the character. They are working drawings in a drafting blue on the page's own paper: measurements with arrowheads, dash-dot centre lines, numbered parts on leaders, construction lines past the corners, colour only ever as coloured hatching. Titles in Bricolage Grotesque, heavy and tight, stand on a drawing's ground line.
217
+
218
+ The garden lives in the structure and in the drawings. Every note has a stage (Rough, Growing, Settled), and the stage picks how its drawings are made: a freehand pencil sketch, the sketch with coloured hatching, an exact drafting with coloured hatching. One Scene is described once and drawn three ways, so the drawing itself tells the reader how finished the note is. Writers never draw; they describe, and a coding agent writes the Scene using the authoring guide under Components.
219
+
220
+ The density is low and the page is flat: no grounds, no panels, no shadows, no grids, no glows, no rasters in the drawings. Plain HTML is the API; a page without Foldkit looks right in both schemes.
221
+
222
+ **Key Characteristics:**
223
+
224
+ - White paper by day, near-black paper by night, followed through `light-dark()` with no script.
225
+ - One column of about 68 characters hung from the left; the space to its right holds margin notes and the drawn title's drawing.
226
+ - Working drawings in a drafting blue, coloured only by hatching in five colours and a pale glass blue.
227
+ - The note's stage picks the drawing's style: sketch, hatched sketch, exact drafting.
228
+ - Bricolage Grotesque 800 for titles and section heads, Atkinson Hyperlegible Next for text, its Mono for code and drawing lettering, Architects Daughter for the writer's hand in margin notes.
229
+ - One movement only: a link's underline firming under the pointer.
230
+
231
+ ## Colors
232
+
233
+ A neutral paper-and-ink palette with the faintest cool cast, one amber accent for freshness, and a separate drawing palette: a drafting blue for every line and six hatching roles. Every colour is a light/dark pair.
234
+
235
+ ### Primary
236
+
237
+ - **Drafting Blue** (draw-line / draw-line-dark): every line, arrowhead, measurement, number, part name and parts list in a drawing, diagrams included, and a margin note's words. On the dark paper it becomes a light blue line. It is the colour of the system's character, and it is never a ground.
238
+
239
+ ### Secondary
240
+
241
+ - **Hatching Red, Blue, Yellow, Green, Brown** (draw-red, draw-blue, draw-yellow, draw-green, draw-brown, each with a -dark pair): coloured hatching laid over a shape in Growing and Settled drawings. Roles a Scene names, not values. Lifted at night so thin lines do not go muddy.
242
+ - **Glass** (draw-glass / draw-glass-dark): a pale blue hatching for water and glass.
243
+
244
+ ### Tertiary
245
+
246
+ - **Amber** (accent / accent-dark): the words New and Updated beside a link. Nothing else.
247
+ - **Highlighter** (mark / mark-dark): `mark`, and the heading, code line, table row, figure caption or footnote a link put the reader on.
248
+ - **Selection** (selection-bg / selection-bg-dark): selected text, in ink.
249
+
250
+ ### Neutral
251
+
252
+ - **Paper** (paper / paper-dark): the page, and what a drawing's `paper` fill hides with.
253
+ - **Ink** (ink / ink-dark): headings, links, strong text, code, the current page in the masthead, the stage mark, the focus ring.
254
+ - **Text** (text / text-dark): running text, a step off the ink for a long read; also a visited link.
255
+ - **Soft Ink** (ink-soft / ink-soft-dark): the meta line, dates, captions, a line about a link, list markers, line numbers, the footer, text buttons at rest.
256
+ - **Rule** (rule / rule-dark): hairlines: `hr`, table rows, a box's top, the ring's top, the quote rule, footnotes.
257
+ - **Wash** (wash / wash-dark): code blocks, inline code, keys.
258
+
259
+ Derived, not separate colours: the link underline is ink at 28% and the soft underline is soft ink at 40%; the scrollbar is soft ink at 70%.
260
+
261
+ ### Named Rules
262
+
263
+ **The Hatching-Only Rule.** Colour enters a drawing as coloured hatching laid over a shape, never as a coloured ground, a flat fill, a wash or a glow. Every drawing sits on the page's own paper.
264
+
265
+ **The One Amber Rule.** The accent marks freshness (New, Updated) and nothing else. Links are ink, told apart by weight and underline, not by hue.
266
+
267
+ **The Pair Rule.** Every colour, drawing colours included, is a `light-dark()` pair in `tokens.css`. A new colour without its dark pair is not finished.
268
+
269
+ ### Forced colours and print
270
+
271
+ - **Forced colours:** a targeted code line or table row takes a 2px inset outline in `Highlight`; stage marks take `CanvasText`; every pencil stroke, ruled line, solid mark, hatching and letter in a `.drawing` takes `CanvasText`, so a drawing (a diagram too) goes monochrome in the system's text colour and still reads by its lines; a margin note's words, like all text, take the forced text colour; task-list boxes return to the native checkbox. The stage word carries the stage either way.
272
+ - **Print:** white paper and black ink whatever the screen's scheme (text black, soft ink #444, wash white, light colour scheme); no body padding; the skip link, masthead, scheme switch, ring and Copy are hidden; an external link prints its address after it. Drawings keep their drafting blue and hatching.
273
+
274
+ ## Typography
275
+
276
+ **Display Font:** Bricolage Grotesque (with Atkinson Hyperlegible Next)
277
+ **Body Font:** Atkinson Hyperlegible Next (with system-ui, sans-serif)
278
+ **Label/Mono Font:** Atkinson Hyperlegible Mono (with ui-monospace, Menlo, Consolas)
279
+ **Hand:** Architects Daughter (with Atkinson Hyperlegible Next)
280
+
281
+ **Character:** A heavy, tight grotesque that can stand on a drawing, over a sans drawn so letters are hard to mistake for one another. The drawings letter in the Mono, in tracked capitals, like a drawing sheet; the writer's margin notes are in a draftsman's hand. All four faces are self-hosted from `fonts/` under the SIL Open Font License.
282
+
283
+ ### Hierarchy
284
+
285
+ - **Display, greeting** (800, clamp(3.5rem, 7.4vw, 7rem), 0.88, -0.045em): the front page's title standing on its drawing (a DrawnTitle outside a note head), at most 6.5ch wide.
286
+ - **Display, note title** (800, clamp(2.75rem, 5.4vw, 5rem), 0.88, -0.045em): a note's title standing on its drawing, at most 9.5ch wide.
287
+ - **Headline** (800, 2.25rem, 1.875rem on a phone, 1.05, -0.03em): an `h1` with no drawing.
288
+ - **Title** (800, 1.75rem, 1.5rem on a phone, 1.05, -0.03em): `h2`, the front page's group heads.
289
+ - **Section** (800, 1.25rem, 1.35): `h2` inside an `article`, a note's section heads.
290
+ - **Standfirst** (Bricolage 500, 1.5rem, 1.3125rem on a phone, 1.3, -0.015em): the line under a title, in ink.
291
+ - **Subtitle** (Atkinson 700, 1.0625rem): `h3`; `h4` to `h6` the same, in italic.
292
+ - **Body** (400, root 17px, 16px under 600px, 1.7): running text at a 34rem measure, about 68 characters. Links 500; strong 700.
293
+ - **Small** (0.9375rem, 1.5): the masthead, a line about a link, tables, footnotes, the ring.
294
+ - **Label** (0.8125rem, 1.55, tabular figures): meta line, dates, captions, figure notes, the sample note, the footer, New and Updated.
295
+ - **Code** (Mono, 0.875em inline, 0.8125rem in a block at 1.65, 0.75rem on a phone).
296
+ - **Parts** (Mono 500, 0.6875rem, 0.08em, uppercase): the parts list under a drawing.
297
+ - **Drawing marks** (Mono 500, 11 viewBox units, 0.08em, uppercase): numbers, measurements and labels inside a drawing; they scale with the drawing.
298
+ - **Hand** (Architects Daughter 400, 0.9375rem, 1.3, centred): a margin note's words; 15 viewBox units for a one-word label inside a margin sketch.
299
+
300
+ ### Named Rules
301
+
302
+ **The Two Voices Rule.** Bricolage is for `h1`, `h2` and the standfirst only; every other word that is read is Atkinson. The display face never sets running text.
303
+
304
+ **The Drawing Sheet Rule.** Words that belong to a drawing (part names, measurements, labels, diagram text) are Mono capitals, tracked, in drafting blue. Words that belong to the writer's pencil are the hand, never capitals.
305
+
306
+ ## Layout
307
+
308
+ The column hangs from the left and stops at the measure (34rem); the masthead, `main` and the page footer all share that width. Body padding is page-top on top, page-left on the left (clamp(1.25rem, 8vw, 7.5rem), so the left edge holds as the screen widens), page-right on the right and page-bottom below. The space to the right of the column is left empty on purpose: margin notes hang in it, and a drawn title's drawing runs out across it.
309
+
310
+ The rhythm is one unit (`--u`, 0.5rem). Blocks are 2.5u apart; figures 3.5u; an `h2` opens 8u above and 1.5u below and clears any right-floated drawing; `h3` 4u above; a box or ring sits 5u from its neighbours under a hairline; the masthead stands 8u above the content (5u on a phone).
311
+
312
+ **Drawn title.** The drawing runs min(75rem, the page inside its side padding and any scrollbar: `body` is an inline-size container and the width is `100cqi`) wide; the `h1` is positioned on the scene's ground line at the left, bottom-anchored, so a longer title grows upward from the ground. The parts list follows, right-aligned to the drawing's width. Under 800px the drawing, cropped to the scene's `focus` range, stands above the title; the title follows under it and the parts list aligns left. The title stays first in the markup, so it is read first.
313
+
314
+ **Margin notes.** At 1100px and over, a margin note floats right out of the column by margin-reach (19rem), 15rem wide, beside the paragraph after it. Under 1100px there is no open space: it floats right inside the column at 9rem, the text wrapping round it, its words under the sketch and its in-drawing labels hidden.
315
+
316
+ **Illustrations.** Full: the measure's width, 4u above and below. Small: floated right at 10rem (at most 40% of the column under 600px), the text wrapping round it.
317
+
318
+ **Small screens (600px and under).** Root 16px, smaller headline, title, standfirst and code; What's new stacks date over line; the ring stacks with All notes last; table cells tighten; long code lines wrap and hang 4ch in past the line number.
319
+
320
+ ### Named Rules
321
+
322
+ **The Hung Column Rule.** The column keeps its left edge and its measure at every width; nothing centres it, and the space to its right is reserved for the drawings, never filled with sidebars or panels.
323
+
324
+ **The No Sideways Push Rule.** Nothing a writer can put in a note pushes the page sideways on a phone: long words break, tables and code scroll inside themselves, drawings scale. The page breaks a long word only once it overflows (`overflow-wrap: break-word`), which a flex or grid row does not see when it sizes its items, so the rows that hold a writer's words (the masthead, a note's meta line, a caption with tools, the parts list, the ring) break a long word anywhere instead.
325
+
326
+ ## Elevation & Depth
327
+
328
+ Flat. There are no shadows, no raised panels and no layered surfaces; the only tonal step is the wash under code. Depth on the page is order and hairlines. Depth inside a drawing is draw order (a later shape hides an earlier one) and the drafting convention of a dashed line for a level, an axis or what is hidden. Two `box-shadow`s in the stylesheet are not elevation: the highlighter's spread around a targeted heading, and the ink edge inset on a targeted code line. A key's 2px bottom border is a key's edge.
329
+
330
+ ### Named Rules
331
+
332
+ **The Own Paper Rule.** Every drawing sits on the page's paper. No blueprint ground, no dot grid, no card behind a drawing, no frame.
333
+
334
+ ## Shapes
335
+
336
+ Square by default. A soft radius (md) on code blocks and images, a smaller one (sm) on inline code, keys, task-list boxes and the focus ring. Divisions are 1px hairlines; a blockquote has a 2px rule on its left. The stage mark is a 12-unit circle at 1.5 stroke: an open ring (Rough), a half disc (Growing), a full disc (Settled). Drawing geometry follows the drawing's stage: tapered, wandering pencil strokes that run past their corners in Rough and Growing; ruled lines, filled arrowheads and dash-dot centre lines in Settled.
337
+
338
+ ## Components
339
+
340
+ The components are Foldkit Views (`X.view(config, h)`) and two Submodels (the scheme switch and Copy), one per directory under `src/`, exported as namespaces from the package (`import { NoteHeader, Scheme } from "@gjermundgaraba-designs/plain-garden"`). Each renders the markup `plain-garden.css` already styles; the classes below are the plain-HTML contract, and the reference for a site without Foldkit is `site/src/example/`: each `.ts` the specimen renders, shown beside the markup it renders, serialised from the same view at build, so the two cannot drift. How a component is built is under "Building components".
341
+
342
+ ### Links and text buttons
343
+
344
+ - **Links:** ink, weight 500, a 1px underline in ink at 28% sitting 0.22em below, firming to full ink under the pointer over 150ms (instant under reduced motion). Visited steps back to the text tone and keeps its weight (not for in-page anchors or the masthead). Inside secondary text (meta, captions, citations, `.note`, `.about`, the footer) links take the surrounding tone and weight over the soft underline. A heading that links to itself stays ink, underlined only under the pointer.
345
+ - **Text buttons** (`.scheme button`, `.copy`): `<button type="button" tabindex="0">`, as `@foldkit/ui`'s Button renders one; no box; soft ink and a soft underline; the one that is on (`aria-pressed="true"`, `aria-disabled="true"`) in ink with no underline.
346
+ - **Focus:** a 2px solid ink ring, 3px off, small radius, on links, buttons, summaries, inputs and every `[tabindex]` region. The `main` a skip link lands on takes focus with no ring: the ring is for what a reader acts on, not the whole column.
347
+
348
+ ### Skip link
349
+
350
+ `SkipLink.view(h)`: `<a class="skip-link" href="#main">Skip to content</a>`, first in `<body>`, before the masthead. Hidden until it has focus, it then shows as a plain link at label size at the column's left edge, centred in the band above the masthead, where it covers nothing. The page's main is `<main id="main">`, so after following the link the next Tab starts inside it.
351
+
352
+ ### Masthead
353
+
354
+ `<header class="masthead">` with `<a class="site-name">` (linking `home`) in ink 700 and `<nav><ul class="site-nav">` of soft-ink links with no underline at rest; the current page (`aria-current="page"` and `data-current`, as `@foldkit/ui`'s Nav marks it) in ink at 500. One wrapping line at the small size. The nav is named "Site" for assistive technology unless the page gives it another name.
355
+
356
+ ### Stage
357
+
358
+ `<span class="stage">` holding the aria-hidden 12-unit mark (`svg.stage-mark`, the same mark a note list uses) and the word (Rough, Growing, Settled). The word always carries the meaning; the mark is drawn, not read.
359
+
360
+ ### Note header
361
+
362
+ `<header class="note-head">`: the title (a DrawnTitle when the note has a drawing, drawn at the note's stage, else a plain `h1`), then `<p class="meta">` with the stage in ink, "Started" and "Updated" dates (written out, en-GB, UTC) and the reading length, then `<p class="standfirst">`.
363
+
364
+ ### Note list
365
+
366
+ `<ul class="note-list">`: each `li` a two-column grid, the stage mark in a 1.5rem column dropped to the title's first line, then the title link, an optional `<span class="flag">` (New or Updated, in amber, label size) and `<p class="about">` with the stage word and one line on what the note holds. The list keeps the writer's order.
367
+
368
+ ### Box, What's new, Pages that link here
369
+
370
+ `<section class="box">`: a hairline above, a small `h2` at the small size, nothing around it. What's new is `<ul class="changes">` inside it: a 9rem date column in soft ink and the line. LinksHere is a box of links headed "Pages that link here".
371
+
372
+ ### Ring
373
+
374
+ `<nav class="ring">` after a note: previous, All notes, next in a three-column grid under a hairline; each keeps its column, so a missing neighbour leaves a gap. Stacks on a phone.
375
+
376
+ ### In short
377
+
378
+ Summary: a plain `h2` ("In short") and an `ol`.
379
+
380
+ ### Figures and code
381
+
382
+ - **Figure:** `<figure id="fig-N">`, the body, `<figcaption>` "**Fig. N.** caption" in soft ink at label size with any tools on the right, then `<ol class="fig-notes">` whose links point into the figure (`fig-N-l5` for a line, `fig-N-<name>` for a group). A note's link reads "Line N" for a line, and a group's name with spaces for its hyphens. A targeted figure's caption takes the highlighter. FigRef links prose to `#fig-N`.
383
+ - **Code figure:** `pre` on the wash with numbered lines (`span.line`, generated numbers that never land in a copy), a focusable scrolling region, Copy that reads Copied for 1.6s and announces it. Where the clipboard is refused it keeps reading Copy, held for the same beat, and its status announces "copy failed". `CopyButton` is a Submodel the page embeds and passes in as the figure's `copy`, which the figure calls with its own name and code: Idle, Copying, then Copied or Failed, then Idle again after the beat. It renders `<button type="button" tabindex="0" class="copy" aria-label="Copy Fig. N">`, with `aria-disabled="true"` and `data-disabled` while it is held, then `<span class="sr-only" role="status">`, both in a `<span>` that carries its id. A targeted line takes the highlighter and a 2px ink edge.
384
+ - **Plain elements:** headings, lists and nested lists, task lists (a small rounded box, ink when done), definition lists, blockquote with `cite`, `kbd`, `mark`, tables (hairlines, tabular figures, scroll inside), images (rounded), footnotes, `details`. All styled with no class.
385
+ - **Note** (`p.note`): a quiet italic line in soft ink for status or provenance; every sample page carries one.
386
+
387
+ ### Drawing (signature)
388
+
389
+ `<svg class="drawing" viewBox="0 0 W H">` holding the scene's marks; with a label it is `role="img"` and `aria-label`, without one `aria-hidden`. The renderer writes classes and the stylesheet colours them from tokens: `pen` (a pencil stroke, a filled shape), `ln` (a ruled line), `solid` (an arrowhead, a dot, an ink fill), `paper` (hides), `faint` (construction lines at 0.45), `hatch` (the line of a hatching pattern, its colour set on it as `--hatch: var(--draw-<colour>)`), `tech` (lettering). Hatching is one `<pattern>` per colour in the drawing's `<defs>`, paper with a line every 4.5 units at 45°, 1.2 thick in the sketch and 1 in the drafting, its id the drawing's own; a hatched shape is a single path filled `url(#…)` with it, under its outline. The sketch's hatching is as regular as the drafting's: the hand is in the outlines. Given a figure number, each named group is a `<g id="fig-N-<name>">`; while a note points at it, its lines are drawn heavier.
390
+
391
+ ### Drawn title
392
+
393
+ `<div class="drawn-title" style="--ground; --focus-width; --focus-start">` holding the `h1` and the drawing, followed by `<ol class="parts">`. See Layout.
394
+
395
+ ### Illustration
396
+
397
+ `<figure class="illustration">` (add `small` to float it right at 10rem): the drawing at the note's stage, its parts list, an italic caption.
398
+
399
+ ### Margin note
400
+
401
+ `<div class="margin-note" role="note">`: an aria-hidden drawing always drawn at Growing, then `<p>` with the writer's words in the hand, centred, in drafting blue. Placed just before the paragraph it points at.
402
+
403
+ ### Diagram
404
+
405
+ A figure the prose reasons about: a numbered Figure holding the scene, always drawn settled, so it reads as exact whatever the note's stage. Each note's `at` names a group in the scene; a followed group's lines are drawn heavier and its words bold. It scales with the column like every drawing, so author it near the column's width (about 520 units) to keep its lettering readable on a phone.
406
+
407
+ ### Parts list
408
+
409
+ `<ol class="parts">`: the numbered parts named in order, Mono capitals at parts size in drafting blue, "1. " generated, wrapping in a row.
410
+
411
+ ### Scheme switch
412
+
413
+ `Scheme.SchemeSwitch`, a Submodel embedded with `h.submodel`: `<p class="scheme" role="group">`, "Colour scheme:" in a `<span>` that names the group, then Light, Dark, System as text buttons (`<button type="button" tabindex="0" aria-pressed="…">`), the one in force `aria-pressed="true"`. System follows the OS with no script; a choice is stored on the device under `plain-garden-scheme` and applied before first paint by `Scheme.schemeScript` inlined in `<head>`, writing `data-scheme` on `<html>`. The switch is self-contained: its `init` returns a `ReadScheme` Command that reads `data-scheme` once the page runs (the client runs init's Commands after hydration), so the application lifts init's Commands into its own init (`Update.foldChildInit`); a choice runs `PinScheme`, which writes or removes `data-scheme` and stores or removes the choice in `localStorage` (storage that refuses leaves the page switched, the choice not remembered). It has no Subscriptions: under System the stylesheet follows the reader's system by itself. A choice made in another tab is seen on reload, not live. `./scheme` exports the script and its keys alone, for a build config that writes `schemeScript` into a page.
414
+
415
+ ### Accessibility
416
+
417
+ - Text at AA in both schemes; running text a step off the ink, secondary text in soft ink, never fainter. The root size is a percentage, so the reader's font size is respected.
418
+ - A stage is never colour or shape alone: the mark is `aria-hidden` and the word is read.
419
+ - Every drawing that says something has `role="img"` and an `aria-label` saying what it shows; decorative ones are `aria-hidden`. A margin note's sketch is decorative and its words are text in `role="note"`. A drawn title's `h1` comes first in the markup even where the drawing shows above it.
420
+ - Code blocks are focusable, labelled scrolling regions; Copy announces Copied, or that the copy failed, through a visually hidden status.
421
+ - Focus is always the 2px ink ring; the only motion stops under `prefers-reduced-motion`.
422
+ - The scheme switch's choice is applied before first paint, so a stored scheme never flashes the other.
423
+ - A skip link is the first thing a keyboard reaches on every page, and it moves focus into `main`.
424
+
425
+ ### Authoring drawings: the guide for agents
426
+
427
+ Writers never draw. A writer says what they want ("a bucket with a tap dripping into a cup, label the parts"); you, the agent, write a `Scene` (`src/drawing/scene.ts`) and put it in the right component. The renderer draws it in the note's stage. You never write SVG paths for a Scene, never draw three versions, and never ask the writer for coordinates.
428
+
429
+ **1. Size the scene for where it will show.** Coordinates are the scene's own units (a viewBox, y down), and drawing lettering is 11 of those units, so design near the displayed pixel width:
430
+
431
+ | Use | Component | Scene size |
432
+ | ------------------------------------ | ------------------------------------------ | -------------------------------- |
433
+ | A page's title on its drawing | `DrawnTitle` (or `NoteHeader`'s `drawing`) | about 1200 wide, 340 to 480 high |
434
+ | A drawing across the measure | `Illustration` | about 640 wide |
435
+ | A small drawing the text wraps round | `Illustration` with `isSmall` | about 180 wide |
436
+ | The writer's pencil in the margin | `MarginNote` | about 240 × 130 |
437
+ | A diagram the prose reasons about | `Diagram` | about 520 wide |
438
+
439
+ **2. Draw clean geometry; the hand comes from the renderer.** Never wobble a line yourself. Shapes:
440
+
441
+ - `rect: [x, y, w, h]`, optional `radius`, optional `turn` (degrees, about its centre).
442
+ - `circle: [cx, cy, r]`.
443
+ - `ellipse: [cx, cy, rx, ry]`; with `from`/`to` (degrees, clockwise from 3 o'clock) it is an open arc, and with `closed: true` too it runs back along its chord (a half disc).
444
+ - `poly: [points]`, optional `open`, optional `turn` (about its centroid). Use `poly` only for true corners: an outlined poly is drawn as one pencil stroke per side, so a many-point poly reads as hairy. Round things are `circle`, `ellipse`, `curve` or `dome`.
445
+ - `curve: [points]`: smooth through its points; `closed: true` to make it a shape.
446
+ - `dome: [cx, baseY, rx, ry]`: half an ellipse on its base (a loaf, a hill).
447
+ - `line: [a, b]`.
448
+ - `arrow: [points]`: two points draw a straight arrow, more a smooth one; the head is on the last point.
449
+ - `text: "words", at: [x, y]`: short words in the drawing itself, centred on `at` as a baseline (under each stack of a pile, "+0.1" by a drop), or starting or ending there with `align: "start"` or `"end"` (a column of notes beside a diagram). Mono capitals in a drawing; the hand in a margin note. Words draw in order like any shape, so put them last to keep them on top.
450
+ - `group: [shapes]` with `origin`, `place`, `scale` and `name`. The group's own `origin` (a point in its shapes' coordinates, usually where the object stands) goes to `place`, and `scale` sizes the group about it; without them it stays where its shapes are. Define a reused object once as a `Shape[]` and note where it stands (the sample `jar` stands at [244, 360] in its own coordinates); then place it anywhere at any size (`origin: [244, 360], place: [60, 100], scale: 0.62` stands it on y = 100 in a margin note). A `name` is what a figure's notes point at (see 13): lower-case letters, digits and hyphens, once per scene, never inside another named group; the renderer refuses anything else.
451
+
452
+ **3. Order is depth.** Later shapes hide earlier ones. A shape with any `fill` hides what is behind it; `fill: "paper"` hides without colour (a wheel's inner disc, a rim, a lid). Draw back to front: handle, body, contents, rim, details.
453
+
454
+ **4. Colour is a role, not a value.**
455
+
456
+ - `red`, `blue`, `yellow`, `green`, `brown`, `glass` (water and glass) become coloured hatching in Growing and Settled, in both schemes. **Rough shows no colour at all:** a coloured shape is a paper-filled outline there. Choose colour for the Growing and Settled drawings.
457
+ - `ink` is solid, for small marks: a hub, a pin, a filled stage mark.
458
+ - Most objects take one colour; leave paper, labels and small details uncoloured.
459
+ - Fill and hatching only apply to closed shapes (`rect`, `circle`, a whole `ellipse`, `poly` that is not `open`, `curve` with `closed: true`, `dome`). A `line`, an open poly, an open curve or an arc never fills.
460
+ - Hatching runs at 45° every 4.5 units, regular and edge to edge, under the outline: a shape under about 10 units wide holds only a line or two. Use `ink` for tiny marks, or make the shape bigger.
461
+
462
+ **5. Stroke.** Default is a full outline. `stroke: "detail"` draws a thinner line (spokes, scoring on a loaf, a cup's handle, a water level, keys). `stroke: "dashed"` draws a dashed line, in every stage: a level, an axis, an edge that is hidden. `stroke: "none"` draws no outline (water inside a bucket, the starter's level in a jar): a blank paper patch in Rough, hatched with no outline in Growing and Settled. Draw a `detail` line along its top edge when the level should read in every stage.
463
+
464
+ **6. Overruns and construction lines.** In Rough and Growing, outlines run about 8 units past their ends, and a sharp `rect` or a closed `poly` with up to six corners gets faint construction lines running 22 units past every corner. Rounded rects, curves and circles get none. The drawing does not clip, so keep sharp-cornered shapes clear of the viewBox edge or accept a spill into the margin; and give a tiny part a `radius` of 2 or 3 so its construction lines do not swamp it.
465
+
466
+ **7. Ground and focus.**
467
+
468
+ - Things stand on a ground. Set `ground` to the y of the line they stand on and draw that line (a `line` across the scene, or a shelf `rect`). It defaults to the scene's height.
469
+ - In a DrawnTitle scene the title stands on the ground at the left, bottom-anchored and growing upward: **keep the left ~45% clear of objects from the ground up.** Put the objects in the right half (the samples start them at x ≈ 540 to 580 of 1200, often by grouping them and moving the group right). Things below the ground (a shelf's brackets) may sit under the title. Leave at least ~300 units above the ground for a three-line title.
470
+ - `focus: [from, to]` is the x-range a phone keeps under 800px, where the drawing is cropped to it and stands above the title. Set it to the objects (the shelf uses [520, 1200]). Without it the whole width shows.
471
+
472
+ **The drafting marks (8 to 10) are shapes too.** Write each beside what it marks, in the same coordinates: inside a group it moves and scales with the group, so a placed object carries its own parts and measurements. Wherever a mark sits in the list, it draws over every shape (centres under measurements under parts). When a group is reused without its marks (the bucket in a margin note), keep the object a plain `Shape[]` and add the marks in a group that wraps it where they are wanted.
473
+
474
+ **8. Parts.** Number the parts a reader should name, in reading order: `{ part: "name", at, tag }`; parts are numbered in the order they appear among the shapes. `at` is a point on the object (a dot is drawn there); `tag` is a point in open space where the numbered ring (radius 10) goes, the leader stopping just short of it. Keep tags 12+ units from the viewBox edge and 22+ apart, and clear of other marks. Names are written in plain lower case; they become the parts list under the drawing, set in capitals. Usually three to six parts; a margin note has none.
475
+
476
+ **9. Measurements: one or two things that matter.**
477
+
478
+ - Linear: `{ measure: [from, to], offset, label }`, add `vertical: true` for a height. A horizontal dimension sits `offset` below the lower point when positive, above the higher one when negative; a vertical one sits right of the rightmost point when positive, left when negative. Extension lines start 4 off the object; arrowheads at both ends; the label sits 6 above the line (rotated for a vertical one). Put it in clear space, off the object.
479
+ - Diameter: `{ diameter: [cx, cy, r], label }`. A leader crosses the circle from lower left to upper right, runs 26 past the rim to a knee and a 46-unit shelf, label on the shelf: leave clear space up and right of the circle. Write labels like "Ø 184".
480
+ - Labels are short: a number ("80", "124") or a word and a number ("cap 10"). They render in capitals.
481
+
482
+ **10. Centres.** `{ centre: [cx, cy, r] }`: a dash-dot cross through a round thing, running 14 past its edge each way. Give the main round things one (a wheel, a flower's head, a pin); more reads as noise.
483
+
484
+ **11. Margin-note scenes.** About 240 × 130 (the samples use 240 × 132; the stages sketch 300 × 124). One object on the right half, and an arrow pointing left at the text, a curve such as `[[100, 112], [64, 128], [16, 112]]`. No parts, no measurements. The note's words are the MarginNote's `words`, never drawn into the scene. A one-word label under a mark is fine; it is lettered in the hand, and it is hidden under 1100px, where the words under the sketch say the same. Margin notes are always drawn at Growing, whatever the note's stage.
485
+
486
+ **12. The scene seeds the hand.** The same scene and stage always draw the same strokes, on the server and in the browser; change the scene and its strokes change. A scene can be shown in any number of places.
487
+
488
+ **13. Which component.**
489
+
490
+ - **DrawnTitle.view**: a page's title standing on its drawing; two elements (the title on its drawing, the parts list), spread into the page. The front page uses it directly; a note passes `drawing: { scene, label }` to NoteHeader and the note's stage draws it.
491
+ - **Illustration.view**: a drawing inside the text, at the note's stage; full measure, or `isSmall` floated right. Put a small one in the section it belongs to (every `h2` clears right floats).
492
+ - **MarginNote.view**: the writer's pencil; place it immediately before the paragraph it points at. Its words are `words`; the sketch is decorative.
493
+ - **Drawing.view**: the bare SVG, for anything else. Give it a label saying what it shows; leave the label out only when it decorates.
494
+ - **Diagram.view**: a figure the prose reasons about, always drawn settled. Put each part a note names, with its words and arrows, in a group with that `name`; the note's `at` is the name. About 520 units wide, so its lettering stays readable when a phone scales it down.
495
+
496
+ **14. Labels for readers.** Every DrawnTitle, Illustration and labelled Drawing needs an `aria-label`-ready sentence saying what the drawing shows, not how it looks ("A bucket of tokens with a tap near its base, dripping into a cup."). Sample drawings start with "Sample drawing:".
497
+
498
+ **Worked example.** The writer: "a bucket with a tap dripping into a cup, label the parts." A full-measure illustration, so 640 wide; the bucket stands on a block so the tap clears the cup.
499
+
500
+ ```ts
501
+ import type { Drawing } from "@gjermundgaraba-designs/plain-garden";
502
+
503
+ export const bucketTapCup: Drawing.Scene = {
504
+ width: 640,
505
+ height: 300,
506
+ ground: 270,
507
+ shapes: [
508
+ // back to front: handle, bucket, water, level, rim, stand, tap, drop, cup
509
+ {
510
+ curve: [
511
+ [200, 70],
512
+ [214, 26],
513
+ [280, 12],
514
+ [346, 26],
515
+ [360, 70],
516
+ ],
517
+ stroke: "detail",
518
+ },
519
+ {
520
+ poly: [
521
+ [196, 60],
522
+ [364, 60],
523
+ [348, 190],
524
+ [212, 190],
525
+ ],
526
+ fill: "blue",
527
+ },
528
+ {
529
+ poly: [
530
+ [201, 100],
531
+ [359, 100],
532
+ [348, 190],
533
+ [212, 190],
534
+ ],
535
+ fill: "glass",
536
+ stroke: "none",
537
+ },
538
+ {
539
+ line: [
540
+ [201, 100],
541
+ [359, 100],
542
+ ],
543
+ stroke: "detail",
544
+ },
545
+ { rect: [188, 52, 184, 12], radius: 6, fill: "paper" },
546
+ { rect: [200, 190, 150, 80], fill: "brown" },
547
+ { rect: [348, 160, 40, 12], radius: 3, fill: "yellow" },
548
+ { rect: [376, 172, 12, 12], radius: 2, fill: "yellow" },
549
+ {
550
+ curve: [
551
+ [382, 200],
552
+ [377, 210],
553
+ [382, 214],
554
+ [387, 210],
555
+ ],
556
+ closed: true,
557
+ fill: "blue",
558
+ },
559
+ {
560
+ curve: [
561
+ [356, 226],
562
+ [358, 256],
563
+ [382, 270],
564
+ [406, 256],
565
+ [408, 226],
566
+ ],
567
+ closed: true,
568
+ fill: "red",
569
+ },
570
+ {
571
+ curve: [
572
+ [408, 232],
573
+ [426, 234],
574
+ [426, 250],
575
+ [404, 256],
576
+ ],
577
+ stroke: "detail",
578
+ },
579
+ {
580
+ line: [
581
+ [20, 270],
582
+ [620, 270],
583
+ ],
584
+ },
585
+ { part: "bucket", at: [330, 120], tag: [430, 40] },
586
+ { part: "tap", at: [372, 166], tag: [470, 120] },
587
+ { part: "cup", at: [390, 250], tag: [490, 210] },
588
+ {
589
+ measure: [
590
+ [196, 60],
591
+ [212, 190],
592
+ ],
593
+ offset: -30,
594
+ label: "130",
595
+ vertical: true,
596
+ },
597
+ {
598
+ measure: [
599
+ [356, 270],
600
+ [408, 270],
601
+ ],
602
+ offset: 18,
603
+ label: "52",
604
+ },
605
+ ],
606
+ };
607
+ ```
608
+
609
+ ```ts
610
+ Illustration.view(
611
+ {
612
+ scene: bucketTapCup,
613
+ stage, // the note's own stage
614
+ label: "A bucket of water on a block, its tap dripping into a cup.",
615
+ caption: "One drop at a time.",
616
+ },
617
+ h,
618
+ );
619
+ ```
620
+
621
+ Why it is built so: the water polygon's top corners sit on the bucket's walls and it has no outline, so Growing and Settled hatch it glass over the bucket's blue; the level `detail` line keeps the water readable in Rough. The rim is a paper-filled rounded rect drawn after the bucket, so it hides the bucket's top edge. The spout has a small radius so its construction lines do not swamp it. Tags sit in the open space to the right, in reading order top to bottom. The cup's width is measured below the ground, clear of the drop; the bucket's height on the left, clear of the tags.
622
+
623
+ ## Building components
624
+
625
+ How a component in this package is made. The components follow these rules, and a new one follows them too; a review finding against one of them is a defect, not a style note.
626
+
627
+ **The two kinds.** A **View** is a stateless render helper, `X.view(config, h)`: the caller owns any state and passes its Messages in the config. Copy `src/ring/` (a plain one), `src/figure/` (a container with a `body` slot and `tools`) or `src/drawnTitle/` (a View over the drawing renderer). A **Submodel** has a Model, Message, `init`, `update` and a `view` made with `defineView`, embedded with `h.submodel`: `src/scheme/` (`switch.ts` holds the Model, Messages, update and the Commands from `init` and `update` that read and pin the scheme on the page; `schemeSwitch.ts` adds the view) and `src/copyButton/` (Commands that write the clipboard and wait out a beat).
628
+
629
+ Each component is `src/<name>/<name>.ts` with an explicit `index.ts` (its public surface: what a page uses, a Submodel's Model, Message, `init`, `update`, `view`, Commands and accessors, and the config types), a colocated `<name>.test.ts` (a Story for update, a Scene for view), an `export * as` line in `src/index.ts`, a section with an example file on the specimen's components page (`site/src/example/`; the page shows its source and the markup it renders) and an entry in this document. Only `src/index.ts` reaches an `index.ts`: inside `src/` a file, tests included, imports the file that defines what it needs (`../stage/stage.ts`). What only other components use has no `index.ts` and is not exported (`src/time/`, the written-out date in a note header and What's new).
630
+
631
+ 1. **A View's config is plain data.** Words are strings (`title`, `caption`, `label`, `words`); a content slot that may hold markup is `ReadonlyArray<Html | string>` (`body`, a note's `body`, a change's `body`, a summary's `points`); a slot that may carry the application's handlers is a function the caller gives, which the View calls with what it knows and which returns the caller's `Html` (a code figure's `copy`, called with the figure's name and code). Booleans read as questions (`isSmall`). A View that renders more than one element (`Summary`, `DrawnTitle` with its parts list) returns `ReadonlyArray<Html>` for the caller to spread.
632
+ 2. **Parents never read a child's Model.** A Submodel exports accessors for what a parent needs (`SchemeSwitch.id`, `CopyButton.id`), and the parent calls them, including for `slotId`.
633
+ 3. **Instances are scoped by id.** A Submodel takes its id in `init({ id })` and scopes its DOM ids by it, so two can share a page.
634
+ 4. **Ids a page addresses are the caller's.** A figure's id is `fig-N` from its number, a note's target `Figure.noteId(figure, at)`; a box's heading id is given (`Box.view({ id })`; `LinksHere`, one per note, is always `links-here`), so a page keeps them unique.
635
+ 5. **Drawings come from the renderer.** `Drawing.view` writes the renderer's marks with `h.InnerHTML`, so the server and the browser draw the same strokes. A View never draws an SVG path of its own; the stage mark is the one exception, three marks in `src/stage/`.
636
+ 6. **Platform services are the application's.** A component that needs one says so in its TSDoc and here (`CopyButton` writes through Effect's `Clipboard`), and the application provides the Layer in its `resources`. A Command that only touches the page it runs on (`SchemeSwitch`'s `ReadScheme` and `PinScheme`, on `<html>` and `localStorage`) needs no service.
637
+ 7. **Fragment links are the browser's.** A link to `#id` (the skip link, a figure's notes, a FigRef) is routed by Foldkit like every click, so a Foldkit application hands a fragment on the page being read back to the browser with `load(href)` from `foldkit/navigation`: a fragment navigation, which scrolls to it and marks it `:target`.
638
+ 8. **A Scene test for every accessibility contract** a component adds: roles, accessible names, `aria-pressed`, `aria-current`, `aria-hidden` on what is drawn and not read, held states, the status a copy announces. A Scene queries the view's tree, not the DOM, so what `h.InnerHTML` writes (a drawing's groups) is tested on the renderer's string instead.
639
+ 9. **Held means `aria-disabled`.** Copy, from the press until it reads Copy again (copying, then Copied or the copy failed for a beat), keeps focus and drops its handler; it is never natively disabled. Buttons are built on `@foldkit/ui`'s `Button.view`, whose `isDisabled` writes the held state (`aria-disabled="true"` and `data-disabled`) and drops the handler.
640
+ 10. **No product in the system.** Routing, storage beyond the scheme choice, and data belong to the site that adopts the system; sample content lives in `site/` only, marked as sample.
641
+
642
+ ## Do's and Don'ts
643
+
644
+ ### Do:
645
+
646
+ - **Do** let the note's stage pick the drawing's style: Rough a freehand pencil sketch with its drafting marks drawn by hand, Growing the sketch with coloured hatching, Settled an exact drafting with ruled lines, filled arrowheads, dash-dot centre lines and the same hatching.
647
+ - **Do** draw every line, measurement and number in drafting blue on the page's own paper, with colour only as hatching in the five colours and glass.
648
+ - **Do** put a parts list under any drawing with numbered parts.
649
+ - **Do** keep margin notes as the writer's pencil: a small hatched sketch, an arrow to the text, a few words in the hand.
650
+ - **Do** stand a title on its drawing's ground line (the front page's greeting on a drafted shelf, a note's title on the line its drawing stands on), keep margin notes in the open space beside the column, and put illustrations inside the text, full measure or small with the text wrapping round.
651
+ - **Do** set headlines and section heads in Bricolage Grotesque 800, tight; keep Atkinson Hyperlegible Next for text.
652
+ - **Do** give every drawing colour a dark pair; at night the drafting blue is a light blue line on the dark paper.
653
+ - **Do** carry a stage as a word as well as a mark, and label every drawing that says something.
654
+ - **Do** keep sample content marked as sample, in source and on the page.
655
+
656
+ ### Don't:
657
+
658
+ - **Don't** use a single highlighter wash as a drawing's only colour.
659
+ - **Don't** put a drawing on a blueprint-blue ground, or on any coloured ground.
660
+ - **Don't** use dot grids or design-tool chrome: selection boxes, handles, frame labels, outline mode.
661
+ - **Don't** make flat cut-paper shapes.
662
+ - **Don't** draw pencil without drafting: a sketch always carries its measurements, centres and numbered parts.
663
+ - **Don't** use painted rasters (gouache, crayon, generated images) for the writer's drawings.
664
+ - **Don't** letter a whole drawing in ballpoint and hand lettering; the hand is for margin notes only.
665
+ - **Don't** trace a faint exact drawing over in pencil.
666
+ - **Don't** bring back any late-90s homepage device: grey grounds, raised white panels, bevelled buttons, Georgia and Verdana, web-safe colours, hazard stripes, boxed layouts.
667
+ - **Don't** use a waving-hand greeting, emoji as bullets, or an "edit ✏️" link, and don't lift copy or illustration style from the concept reference.
668
+ - **Don't** add shadows, glows, cards or panels; the page is flat and hung from the left.
669
+ - **Don't** use the amber for anything but New and Updated, or colour links by hue.
670
+ - **Don't** wobble a Scene's coordinates by hand or write three versions of a drawing; describe it once and let the stage draw it.
671
+ - **Don't** add a logo, wordmark or identity beyond the name plain-garden.