@bongos/core 1.19.449 → 1.19.451
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.
- package/.bongos-core.json +59 -29
- package/docs/copy-inventory.md +67 -71
- package/docs/copy-registry.json +135 -221
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/diagram-viewer.css +51 -34
- package/modules/hall-ui/public/diagram-viewer.js +4 -1
- package/modules/hall-ui/public/diagrams.css +45 -0
- package/modules/hall-ui/public/diagrams.html +12 -20
- package/modules/hall-ui/public/diagrams.states.json +28 -0
- package/modules/hall-ui/public/primer.css +92 -400
- package/modules/hall-ui/public/primer.html +68 -26
- package/modules/hall-ui/public/primer.js +107 -308
- package/modules/hall-ui/public/primer.states.json +38 -0
- package/modules/hall-ui/public/ranks.html +9 -1
- package/modules/hall-ui/public/ranks.states.json +1 -1
- package/modules/hall-ui/public/roadmap.css +152 -86
- package/modules/hall-ui/public/roadmap.html +6 -1
- package/modules/hall-ui/public/roadmap.states.json +31 -0
- package/modules/hall-ui/public/room.css +441 -0
- package/modules/hall-ui/public/style.css +96 -24
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/land-watch.js +28 -9
- package/scripts/hall-preview/server.js +29 -0
- package/src/module-api.js +1 -1
- package/tests/hall_audit.mjs +14 -10
- package/tests/hall_reading_world.mjs +430 -0
- package/tests/land_watch.mjs +48 -3
|
@@ -1,417 +1,109 @@
|
|
|
1
|
-
/* primer.css — the
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.primer-layout {
|
|
34
|
-
display: grid;
|
|
35
|
-
grid-template-columns: 240px minmax(0, 1fr);
|
|
36
|
-
gap: 40px;
|
|
37
|
-
align-items: start;
|
|
38
|
-
padding-bottom: 24px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/* ---------- Sticky table of contents (left rail) ---------- */
|
|
42
|
-
|
|
43
|
-
.primer-toc {
|
|
44
|
-
position: sticky;
|
|
45
|
-
top: calc(var(--topbar-h) + 16px);
|
|
46
|
-
align-self: start;
|
|
47
|
-
}
|
|
48
|
-
.primer-toc__toggle {
|
|
49
|
-
display: none;
|
|
50
|
-
width: 100%;
|
|
51
|
-
padding: 9px 14px;
|
|
52
|
-
background: var(--surface);
|
|
53
|
-
border: 1px solid var(--border-strong);
|
|
54
|
-
border-radius: var(--radius-sm);
|
|
55
|
-
font-family: var(--font-body);
|
|
56
|
-
font-size: 13.5px;
|
|
57
|
-
font-weight: 600;
|
|
58
|
-
color: var(--ink);
|
|
59
|
-
cursor: pointer;
|
|
60
|
-
justify-content: space-between;
|
|
61
|
-
align-items: center;
|
|
62
|
-
}
|
|
63
|
-
.primer-toc__chevron {
|
|
64
|
-
transition: transform 200ms;
|
|
65
|
-
}
|
|
66
|
-
.primer-toc__toggle[aria-expanded="true"] .primer-toc__chevron {
|
|
67
|
-
transform: rotate(180deg);
|
|
68
|
-
}
|
|
69
|
-
.primer-toc__inner {
|
|
70
|
-
background: var(--surface);
|
|
71
|
-
border: 1px solid var(--border);
|
|
72
|
-
border-radius: var(--radius);
|
|
73
|
-
padding: 16px 16px 18px;
|
|
74
|
-
}
|
|
75
|
-
.primer-toc__heading {
|
|
76
|
-
margin: 0 0 10px;
|
|
77
|
-
font-size: 11.5px;
|
|
78
|
-
font-weight: 600;
|
|
79
|
-
letter-spacing: 0.06em;
|
|
80
|
-
text-transform: uppercase;
|
|
81
|
-
color: var(--ink-faint);
|
|
82
|
-
border-bottom: 1px solid var(--border);
|
|
83
|
-
padding-bottom: 8px;
|
|
84
|
-
}
|
|
85
|
-
.primer-toc__list {
|
|
86
|
-
list-style: none;
|
|
87
|
-
margin: 0;
|
|
88
|
-
padding: 0;
|
|
89
|
-
counter-reset: toc;
|
|
90
|
-
}
|
|
91
|
-
.primer-toc__list li {
|
|
92
|
-
margin: 0;
|
|
93
|
-
padding: 4px 0;
|
|
94
|
-
counter-increment: toc;
|
|
95
|
-
line-height: 1.4;
|
|
96
|
-
}
|
|
97
|
-
.primer-toc__list a {
|
|
98
|
-
/* Two-column grid: a fixed-width numeral gutter wide enough for the
|
|
99
|
-
longest Roman numeral in any primer (VIII = 3 letters), then the
|
|
100
|
-
section title flows in column 2. Grid keeps the two columns
|
|
101
|
-
independent so long numerals never overlap the title. */
|
|
102
|
-
display: grid;
|
|
103
|
-
grid-template-columns: 2.4em 1fr;
|
|
104
|
-
column-gap: 0.4em;
|
|
105
|
-
font-size: 13.5px;
|
|
106
|
-
color: var(--ink-soft);
|
|
107
|
-
transition: color 150ms;
|
|
108
|
-
}
|
|
109
|
-
.primer-toc__list a::before {
|
|
110
|
-
content: counter(toc, upper-roman) ".";
|
|
111
|
-
font-size: 12px;
|
|
112
|
-
color: var(--ink-faint);
|
|
113
|
-
letter-spacing: 0.03em;
|
|
114
|
-
text-align: right;
|
|
115
|
-
/* Align the period baseline with the title's first line. */
|
|
116
|
-
line-height: 1.4;
|
|
117
|
-
}
|
|
118
|
-
.primer-toc__list a:hover {
|
|
119
|
-
color: var(--ink);
|
|
120
|
-
text-decoration: none;
|
|
121
|
-
}
|
|
122
|
-
.primer-toc__list a.is-active {
|
|
123
|
-
color: var(--accent-text);
|
|
124
|
-
font-weight: 600;
|
|
125
|
-
}
|
|
126
|
-
.primer-toc__list a.is-active::before {
|
|
127
|
-
color: var(--accent-text);
|
|
128
|
-
}
|
|
129
|
-
.primer-toc__placeholder {
|
|
130
|
-
color: var(--ink-faint);
|
|
131
|
-
padding: 4px 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/* ---------- Article column ---------- */
|
|
135
|
-
|
|
136
|
-
.primer-article {
|
|
137
|
-
/* Reading-optimized line length. Roughly 60-72ch at 17px body. */
|
|
138
|
-
max-width: 72ch;
|
|
139
|
-
font-size: 1.05rem;
|
|
140
|
-
line-height: 1.7;
|
|
141
|
-
color: var(--ink);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.primer-loading {
|
|
145
|
-
color: var(--ink-soft);
|
|
146
|
-
padding: 40px 0;
|
|
147
|
-
text-align: center;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.primer-article h1 {
|
|
151
|
-
/* The primer's own H1 — suppressed; the top bar already names the page. */
|
|
152
|
-
display: none;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.primer-article h2 {
|
|
156
|
-
font-family: var(--font-display);
|
|
157
|
-
font-weight: 700;
|
|
158
|
-
font-size: 1.45rem;
|
|
159
|
-
letter-spacing: -0.01em;
|
|
160
|
-
color: var(--ink);
|
|
161
|
-
margin: 2.4em 0 0.7em;
|
|
162
|
-
padding-bottom: 0.45em;
|
|
163
|
-
border-bottom: 1px solid var(--border);
|
|
164
|
-
/* Anchor jumps must land below the sticky top bar. */
|
|
165
|
-
scroll-margin-top: calc(var(--topbar-h) + 16px);
|
|
166
|
-
}
|
|
167
|
-
.primer-article h2:first-of-type {
|
|
168
|
-
margin-top: 0.4em;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.primer-article h3 {
|
|
1
|
+
/* primer.css — what the PRIMER has that the other reading rooms do not
|
|
2
|
+
(V3.R13-followup #406; rebuilt into the chrome world by task 1003306).
|
|
3
|
+
|
|
4
|
+
The room itself — the reading measure and rhythm, the table of contents, the
|
|
5
|
+
progress hairline, the framed figure, the skeleton and the failure note — is
|
|
6
|
+
the shared archetype in room.css, which this page loads first. What is left
|
|
7
|
+
here is the acknowledge gate: the primer is the one document in the hall a
|
|
8
|
+
builder must confirm they have read, and no other room has one.
|
|
9
|
+
|
|
10
|
+
Three things this sheet used to carry that are gone rather than moved:
|
|
11
|
+
* `body.primer-body { background: var(--bg) }` — the shell paints the
|
|
12
|
+
ground now; a page repainting it is a second copy of a value that already
|
|
13
|
+
has an owner. The class stays on <body> because it is a page hook, not a
|
|
14
|
+
paint.
|
|
15
|
+
* `max-width: 72ch` on the article, under a comment reading "Roughly 60-72ch
|
|
16
|
+
at 17px body". A `ch` is the font's ZERO glyph, not a character, and
|
|
17
|
+
Manrope's zero is wide: it rendered about 90. The measure is the shell's
|
|
18
|
+
measured --measure, and it lives in room.css with the prose.
|
|
19
|
+
* A hand-written `z-index: 25` on the progress bar. It is --z-progress now,
|
|
20
|
+
named in the shell's ladder beside the topbar it has to sit under.
|
|
21
|
+
|
|
22
|
+
No compat alias (--surface / --surface-2 / --border / --border-strong /
|
|
23
|
+
--accent-weak / --accent-text) appears here. `--line` is a WIDTH; the
|
|
24
|
+
hairline's colour is --rule / --rule-soft. */
|
|
25
|
+
|
|
26
|
+
/* ---- the acknowledge gate ------------------------------------------------
|
|
27
|
+
Its own card under the article, at the same width, so the end of the document
|
|
28
|
+
and the thing to do about it read as two beats of one column. */
|
|
29
|
+
|
|
30
|
+
.primer-ack { margin: var(--sp-sm) 0 var(--sp-xl); padding: var(--room-pad); }
|
|
31
|
+
.primer-ack__h {
|
|
32
|
+
margin: 0 0 14px;
|
|
172
33
|
font-family: var(--font-display);
|
|
173
|
-
font-weight:
|
|
174
|
-
font-size:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
scroll-margin-top: calc(var(--topbar-h) + 16px);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.primer-article p {
|
|
181
|
-
margin: 0 0 1.15em;
|
|
182
|
-
}
|
|
183
|
-
.primer-article p:last-child { margin-bottom: 0; }
|
|
184
|
-
|
|
185
|
-
/* The subtitle line at the very top of the primer markdown. */
|
|
186
|
-
.primer-article > p > em:only-child {
|
|
187
|
-
font-size: 1.02rem;
|
|
188
|
-
color: var(--ink-soft);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.primer-article a {
|
|
192
|
-
color: var(--accent-text);
|
|
193
|
-
border-bottom: 1px solid var(--border);
|
|
194
|
-
}
|
|
195
|
-
.primer-article a:hover {
|
|
196
|
-
color: var(--accent);
|
|
197
|
-
border-bottom-color: var(--accent);
|
|
198
|
-
text-decoration: none;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.primer-article strong {
|
|
34
|
+
font-weight: 300;
|
|
35
|
+
font-size: 28px;
|
|
36
|
+
line-height: 1.1;
|
|
37
|
+
letter-spacing: -0.03em;
|
|
202
38
|
color: var(--ink);
|
|
203
|
-
font-weight: 600;
|
|
204
|
-
}
|
|
205
|
-
.primer-article em {
|
|
206
|
-
font-style: italic;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.primer-article code {
|
|
210
|
-
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
211
|
-
font-size: 0.92em;
|
|
212
|
-
background: var(--surface-2);
|
|
213
|
-
border: 1px solid var(--border);
|
|
214
|
-
padding: 1px 5px;
|
|
215
|
-
border-radius: 4px;
|
|
216
|
-
color: var(--accent-text);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.primer-article pre {
|
|
220
|
-
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
221
|
-
font-size: 0.9em;
|
|
222
|
-
line-height: 1.55;
|
|
223
|
-
background: var(--surface-2);
|
|
224
|
-
border: 1px solid var(--border);
|
|
225
|
-
border-radius: var(--radius-sm);
|
|
226
|
-
padding: 14px 16px;
|
|
227
|
-
margin: 1.4em 0;
|
|
228
|
-
overflow-x: auto;
|
|
229
|
-
color: var(--ink);
|
|
230
|
-
}
|
|
231
|
-
.primer-article pre code {
|
|
232
|
-
background: none;
|
|
233
|
-
border: none;
|
|
234
|
-
padding: 0;
|
|
235
|
-
color: inherit;
|
|
236
|
-
font-size: inherit;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.primer-article ul, .primer-article ol {
|
|
240
|
-
margin: 0 0 1.2em;
|
|
241
|
-
padding-left: 1.4em;
|
|
242
39
|
}
|
|
243
|
-
.primer-
|
|
244
|
-
margin: 0 0
|
|
245
|
-
|
|
246
|
-
.primer-article li:last-child { margin-bottom: 0; }
|
|
247
|
-
|
|
248
|
-
.primer-article hr {
|
|
249
|
-
border: none;
|
|
250
|
-
border-top: 1px solid var(--border);
|
|
251
|
-
margin: 2.4em 0;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/* Tables (the rank ladder). Styled like .ledger but reading-tuned. */
|
|
255
|
-
.primer-article table {
|
|
256
|
-
width: 100%;
|
|
257
|
-
border-collapse: collapse;
|
|
258
|
-
margin: 1.4em 0;
|
|
259
|
-
font-size: 0.95em;
|
|
260
|
-
}
|
|
261
|
-
.primer-article th, .primer-article td {
|
|
262
|
-
text-align: left;
|
|
263
|
-
padding: 10px 12px;
|
|
264
|
-
border-bottom: 1px solid var(--border);
|
|
265
|
-
vertical-align: top;
|
|
266
|
-
}
|
|
267
|
-
.primer-article th {
|
|
268
|
-
font-size: 0.78em;
|
|
269
|
-
font-weight: 600;
|
|
270
|
-
letter-spacing: 0.05em;
|
|
271
|
-
text-transform: uppercase;
|
|
40
|
+
.primer-ack__lede {
|
|
41
|
+
margin: 0 0 var(--sp-md);
|
|
42
|
+
max-width: var(--measure);
|
|
272
43
|
color: var(--ink-soft);
|
|
273
|
-
background: var(--surface-2);
|
|
274
44
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
text-
|
|
284
|
-
}
|
|
285
|
-
.primer-figure img {
|
|
286
|
-
max-width: 100%;
|
|
287
|
-
height: auto;
|
|
288
|
-
background: var(--surface);
|
|
289
|
-
border: 1px solid var(--border);
|
|
290
|
-
border-radius: var(--radius-sm);
|
|
291
|
-
padding: 12px;
|
|
292
|
-
}
|
|
293
|
-
.primer-figure figcaption {
|
|
294
|
-
margin-top: 10px;
|
|
295
|
-
font-size: 12.5px;
|
|
45
|
+
/* The gate is a MEASUREMENT the reader can watch move, not a refusal: the meter
|
|
46
|
+
says how far through the article they are against the threshold, in the label
|
|
47
|
+
voice, with the figure tabular so it does not re-space as it counts up. */
|
|
48
|
+
.primer-ack__meter {
|
|
49
|
+
margin: 0 0 var(--sp-lg);
|
|
50
|
+
font-family: var(--label-face);
|
|
51
|
+
font-size: var(--label-size);
|
|
52
|
+
letter-spacing: var(--label-space);
|
|
53
|
+
text-transform: var(--label-case);
|
|
296
54
|
color: var(--ink-faint);
|
|
297
55
|
}
|
|
56
|
+
.primer-ack__num { color: var(--ink); font-variant-numeric: tabular-nums; }
|
|
298
57
|
|
|
299
|
-
/*
|
|
300
|
-
|
|
301
|
-
.
|
|
302
|
-
|
|
303
|
-
margin: 24px auto 40px;
|
|
304
|
-
}
|
|
305
|
-
.primer-ack__inner {
|
|
306
|
-
background: var(--surface);
|
|
307
|
-
border: 1px solid var(--border);
|
|
308
|
-
border-radius: var(--radius);
|
|
309
|
-
padding: 30px 28px;
|
|
310
|
-
text-align: center;
|
|
311
|
-
}
|
|
312
|
-
.primer-ack__h {
|
|
313
|
-
font-family: var(--font-display);
|
|
314
|
-
font-weight: 600;
|
|
315
|
-
font-size: 1.15rem;
|
|
316
|
-
color: var(--ink);
|
|
317
|
-
margin: 0 0 10px;
|
|
318
|
-
}
|
|
319
|
-
.primer-ack__lede {
|
|
320
|
-
margin: 0 0 20px;
|
|
321
|
-
color: var(--ink-soft);
|
|
322
|
-
font-size: 14px;
|
|
323
|
-
}
|
|
58
|
+
/* The locked state is glass, the open state is the accent — the One Warm Thing
|
|
59
|
+
Rule: the accent lights only what is pressable, and while the gate is shut
|
|
60
|
+
this is not. aria-disabled (not disabled) keeps the control in the tab order
|
|
61
|
+
so a keyboard reader can land on it and hear the note below say why. */
|
|
324
62
|
.primer-ack__btn {
|
|
325
|
-
display: inline-
|
|
326
|
-
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
min-height: 48px;
|
|
66
|
+
padding: 0 30px;
|
|
327
67
|
font-family: var(--font-body);
|
|
328
|
-
font-size:
|
|
329
|
-
font-weight: 600;
|
|
330
|
-
color: #fff;
|
|
331
|
-
background: var(--accent);
|
|
332
|
-
border: 1px solid var(--accent-deep);
|
|
333
|
-
border-radius: var(--radius-sm);
|
|
334
|
-
cursor: pointer;
|
|
335
|
-
transition: background 150ms, transform 100ms;
|
|
336
|
-
}
|
|
337
|
-
.primer-ack__btn:hover:not(:disabled) {
|
|
338
|
-
background: var(--accent-deep);
|
|
339
|
-
}
|
|
340
|
-
.primer-ack__btn:active:not(:disabled) {
|
|
341
|
-
transform: translateY(1px);
|
|
342
|
-
}
|
|
343
|
-
.primer-ack__btn:disabled {
|
|
344
|
-
background: var(--surface-2);
|
|
68
|
+
font-size: 15px;
|
|
345
69
|
color: var(--ink-faint);
|
|
346
|
-
|
|
70
|
+
background: var(--glass);
|
|
71
|
+
border: var(--line) solid var(--glass-edge);
|
|
72
|
+
border-radius: var(--radius-pill);
|
|
347
73
|
cursor: not-allowed;
|
|
74
|
+
transition: color 200ms cubic-bezier(.2, .7, .3, 1), background 200ms cubic-bezier(.2, .7, .3, 1);
|
|
348
75
|
}
|
|
349
|
-
.primer-
|
|
350
|
-
|
|
351
|
-
color: var(--
|
|
76
|
+
.primer-ack__btn[aria-disabled="false"] {
|
|
77
|
+
background: var(--accent);
|
|
78
|
+
border-color: var(--accent);
|
|
79
|
+
color: var(--accent-on);
|
|
80
|
+
cursor: pointer;
|
|
352
81
|
}
|
|
82
|
+
.primer-ack__btn[aria-disabled="false"]:hover { background: var(--accent-lift); }
|
|
353
83
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
.primer-ack__inner--acked .primer-ack__h {
|
|
361
|
-
margin-bottom: 6px;
|
|
362
|
-
font-size: 1rem;
|
|
363
|
-
}
|
|
364
|
-
.primer-ack__inner--acked .primer-ack__note {
|
|
365
|
-
margin-top: 0;
|
|
366
|
-
color: var(--ink);
|
|
84
|
+
.primer-ack__note {
|
|
85
|
+
margin: var(--sp-sm) 0 0;
|
|
86
|
+
max-width: var(--measure);
|
|
87
|
+
font-size: 13.5px;
|
|
88
|
+
color: var(--ink-faint);
|
|
367
89
|
}
|
|
368
|
-
.primer-ack__check {
|
|
90
|
+
.primer-ack__check { margin-right: 6px; color: var(--ok); font-weight: 600; }
|
|
91
|
+
/* The way back, once the gate is closed. It is a link in a sentence with no
|
|
92
|
+
vertical rhythm of its own — measured 84x18 in the acked state — so it takes
|
|
93
|
+
the shell's remedy for exactly that shape (.scroll__lede a in style.css):
|
|
94
|
+
go inline-block and buy the height back with padding the line does not pay
|
|
95
|
+
for. The class is this page's, so the rule is too. */
|
|
96
|
+
.primer-ack__note a {
|
|
369
97
|
display: inline-block;
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
.primer-toc {
|
|
384
|
-
position: static;
|
|
385
|
-
margin-bottom: 20px;
|
|
386
|
-
}
|
|
387
|
-
.primer-toc__toggle {
|
|
388
|
-
display: flex;
|
|
389
|
-
}
|
|
390
|
-
.primer-toc__inner {
|
|
391
|
-
display: none;
|
|
392
|
-
margin-top: 6px;
|
|
393
|
-
}
|
|
394
|
-
.primer-toc.is-open .primer-toc__inner {
|
|
395
|
-
display: block;
|
|
396
|
-
}
|
|
397
|
-
.primer-article {
|
|
398
|
-
font-size: 1rem;
|
|
399
|
-
line-height: 1.65;
|
|
400
|
-
}
|
|
401
|
-
.primer-article h2 {
|
|
402
|
-
font-size: 1.25rem;
|
|
403
|
-
}
|
|
404
|
-
/* A markdown table's column count is fixed by the source, so its min-content
|
|
405
|
-
width outruns a phone (measured: 79px of page overflow on /drachmae). Give
|
|
406
|
-
the table its own horizontal scroller instead of letting it drag the page
|
|
407
|
-
sideways — the .section-rail / .kit-tabs strips already set that precedent.
|
|
408
|
-
`display: block` is what makes the table box a scrollport; the rows still
|
|
409
|
-
lay out through the anonymous table box inside it. Nothing here is sticky,
|
|
410
|
-
so this costs no header behaviour. */
|
|
411
|
-
.primer-article table {
|
|
412
|
-
display: block;
|
|
413
|
-
width: max-content;
|
|
414
|
-
max-width: 100%;
|
|
415
|
-
overflow-x: auto;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
98
|
+
min-width: 24px;
|
|
99
|
+
min-height: 24px;
|
|
100
|
+
padding: 3px 4px;
|
|
101
|
+
margin: 0 -4px;
|
|
102
|
+
line-height: 18px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* V3.R13-followup-2 (#411): the acked panel collapses — no big button, no
|
|
106
|
+
lede, just the confirmation line, so a re-read is not shouted at. */
|
|
107
|
+
.primer-ack--acked { padding: var(--sp-md) var(--sp-lg); }
|
|
108
|
+
.primer-ack--acked .primer-ack__h { margin-bottom: 6px; font-size: 20px; }
|
|
109
|
+
.primer-ack--acked .primer-ack__note { margin-top: 0; color: var(--ink-soft); }
|
|
@@ -9,15 +9,14 @@
|
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
12
|
+
<link rel="stylesheet" href="/builders/room.css">
|
|
12
13
|
<link rel="stylesheet" href="/builders/primer.css?v=2026-07-02-shell1">
|
|
13
14
|
<link rel="stylesheet" href="/builders/diagram-viewer.css?v=2026-06-14-diagviewer-1">
|
|
14
15
|
</head>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
the content column's progress, not app chrome). -->
|
|
20
|
-
<div class="primer-progress" aria-hidden="true"><div class="primer-progress__bar" id="primer-progress-bar"></div></div>
|
|
16
|
+
<!-- `room` opts this page into the reading-room archetype's composition tokens
|
|
17
|
+
(room.css). They sit on the body, never in a page :root — the branding
|
|
18
|
+
pack's :root is spliced at the end of <head> and outranks one. -->
|
|
19
|
+
<body class="room primer-body" data-page="primer" data-page-title="Primer">
|
|
21
20
|
|
|
22
21
|
<div class="app">
|
|
23
22
|
<aside class="app-sidebar" id="app-sidebar" aria-label="Primary"></aside>
|
|
@@ -26,19 +25,34 @@
|
|
|
26
25
|
<header class="app-topbar" id="app-topbar"></header>
|
|
27
26
|
<div class="app-content">
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
<!-- Reading-progress hairline — fills as the reader scrolls the article.
|
|
29
|
+
Sticky under the topbar rather than fixed over the viewport: it is the
|
|
30
|
+
content column's progress, not app chrome, and --z-progress puts it
|
|
31
|
+
below the topbar in the ladder for the same reason. -->
|
|
32
|
+
<div class="primer-progress" aria-hidden="true"><div class="primer-progress__bar" id="primer-progress-bar"></div></div>
|
|
33
|
+
|
|
34
|
+
<!-- The reading room announces its document: the label voice on a
|
|
35
|
+
one-word eyebrow, then the room's name lowercase in the display face.
|
|
36
|
+
The board's head is deliberately the quiet inverse of this — see
|
|
37
|
+
.page-head--room in style.css. The page had no <h1> at all before
|
|
38
|
+
task 1003306, so it failed one-header-main-h1 on every render. -->
|
|
39
|
+
<div class="page-head page-head--room">
|
|
40
|
+
<p class="page-head__eyebrow">Docs</p>
|
|
41
|
+
<h1 class="page-head__h">The primer</h1>
|
|
30
42
|
<p class="page-head__sub">Everything a new builder needs before claiming their first task. About a ten-minute read.</p>
|
|
31
43
|
</div>
|
|
32
44
|
|
|
33
45
|
<main id="hall-main">
|
|
34
46
|
<div class="primer-layout">
|
|
35
47
|
|
|
36
|
-
<!-- Sticky left-rail table of contents. Built from the article's h2s
|
|
37
|
-
the markdown renders
|
|
48
|
+
<!-- Sticky left-rail table of contents. Built from the article's h2s
|
|
49
|
+
after the markdown renders; the numerals are drawn by room.css's
|
|
50
|
+
counter, so the markup carries only titles. Mobile: collapses
|
|
51
|
+
behind a toggle. -->
|
|
38
52
|
<aside class="primer-toc" id="primer-toc" aria-label="Sections in this primer">
|
|
39
53
|
<button type="button" class="primer-toc__toggle" id="primer-toc-toggle" aria-expanded="false" aria-controls="primer-toc-list">
|
|
40
54
|
<span>Sections</span>
|
|
41
|
-
<
|
|
55
|
+
<svg class="primer-toc__chevron" viewBox="0 0 10 6" width="10" height="6" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 1.2 5 4.8 9 1.2"/></svg>
|
|
42
56
|
</button>
|
|
43
57
|
<nav class="primer-toc__inner">
|
|
44
58
|
<p class="primer-toc__heading" id="primer-toc-heading">In this primer</p>
|
|
@@ -48,25 +62,50 @@
|
|
|
48
62
|
</nav>
|
|
49
63
|
</aside>
|
|
50
64
|
|
|
51
|
-
<!--
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</article>
|
|
65
|
+
<!-- The article column. Three panels of the same card at the same
|
|
66
|
+
width — skeleton, document, failure — so the column never changes
|
|
67
|
+
shape as the markdown resolves. -->
|
|
68
|
+
<div class="primer-col">
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
<div class="primer-skeleton scroll" id="primer-skeleton" aria-hidden="true">
|
|
71
|
+
<span class="primer-sk primer-skeleton__h"></span>
|
|
72
|
+
<div class="primer-skeleton__p">
|
|
73
|
+
<span class="primer-sk"></span><span class="primer-sk"></span>
|
|
74
|
+
<span class="primer-sk"></span><span class="primer-sk"></span>
|
|
75
|
+
<span class="primer-sk"></span>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="primer-skeleton__rule"></div>
|
|
78
|
+
<div class="primer-skeleton__p">
|
|
79
|
+
<span class="primer-sk"></span><span class="primer-sk"></span>
|
|
80
|
+
<span class="primer-sk"></span><span class="primer-sk"></span>
|
|
81
|
+
<span class="primer-sk"></span>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<article class="primer-article scroll" id="primer-article" aria-busy="true" hidden></article>
|
|
86
|
+
|
|
87
|
+
<div class="primer-note primer-note--error scroll" id="primer-error" hidden>
|
|
88
|
+
<p class="primer-note__label">The primer did not load</p>
|
|
89
|
+
<p class="primer-note__body">The markdown behind this page could not be fetched. Reload to try again, or read it in the repo.</p>
|
|
90
|
+
<p class="primer-note__acts"><a class="btn btn--ghost" href="/builders">Back to home</a></p>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Footer ack module. The button is soft-gated with aria-disabled
|
|
94
|
+
(NOT disabled) until the reader has scrolled past ~90% of the
|
|
95
|
+
article: a real disabled button leaves the tab order, so a
|
|
96
|
+
keyboard reader could never land on it and never heard why it
|
|
97
|
+
was locked. -->
|
|
98
|
+
<section class="primer-ack scroll" id="primer-ack" aria-labelledby="primer-ack-h" hidden>
|
|
99
|
+
<h2 class="primer-ack__h" id="primer-ack-h">Acknowledge the primer</h2>
|
|
100
|
+
<p class="primer-ack__lede" id="primer-ack-lede">Read to the end and the button below unlocks. It is an honour system — nothing here checks your comprehension.</p>
|
|
101
|
+
<p class="primer-ack__meter" id="primer-ack-meter">Read <span class="primer-ack__num">0%</span> of the 90% needed</p>
|
|
102
|
+
<button type="button" class="primer-ack__btn" id="primer-ack-btn" aria-disabled="true" aria-describedby="primer-ack-note-locked">I have read it</button>
|
|
103
|
+
<p class="primer-ack__note" id="primer-ack-note-locked">Locked until you reach the end of the article above.</p>
|
|
104
|
+
<p class="primer-ack__note" id="primer-ack-note" hidden></p>
|
|
105
|
+
</section>
|
|
58
106
|
|
|
59
|
-
<!-- Footer ack module — sits below the article. Button is soft-gated (disabled
|
|
60
|
-
class) until the reader has scrolled past ~90% of the content. The honor-
|
|
61
|
-
system signal: "I have read it" only enables once they've actually read it. -->
|
|
62
|
-
<section class="primer-ack" id="primer-ack" hidden>
|
|
63
|
-
<div class="primer-ack__inner">
|
|
64
|
-
<h2 class="primer-ack__h">Acknowledge the primer</h2>
|
|
65
|
-
<p class="primer-ack__lede" id="primer-ack-lede">Scroll through the primer above. Once you've reached the end, the button below activates.</p>
|
|
66
|
-
<button type="button" class="primer-ack__btn" id="primer-ack-btn" disabled>I have read it</button>
|
|
67
|
-
<p class="primer-ack__note" id="primer-ack-note" hidden>Already acknowledged — you're all set. <a href="/">Back to home</a>.</p>
|
|
68
107
|
</div>
|
|
69
|
-
</
|
|
108
|
+
</div>
|
|
70
109
|
</main>
|
|
71
110
|
|
|
72
111
|
<footer class="app-foot" id="app-foot"></footer>
|
|
@@ -79,6 +118,9 @@
|
|
|
79
118
|
<script src="/builders/shell.js?v=2026-07-02-shell1"></script>
|
|
80
119
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
81
120
|
<script src="/builders/palette.js" defer></script>
|
|
121
|
+
<!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
|
|
122
|
+
it rather than carrying a second copy of the grammar. -->
|
|
123
|
+
<script src="/builders/md-reader.js" defer></script>
|
|
82
124
|
<script src="/builders/primer.js?v=2026-05-29-primer-1" defer></script>
|
|
83
125
|
<script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
|
|
84
126
|
<script src="/builders/copy-on-click.js?v=2026-06-01-copy-1" defer></script>
|