@bongos/core 1.19.448 → 1.19.450

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 (42) hide show
  1. package/.bongos-core.json +96 -36
  2. package/docs/copy-inventory.md +121 -114
  3. package/docs/copy-registry.json +377 -331
  4. package/docs/file-map.md +1 -1
  5. package/docs/module-api-changelog.md +4 -0
  6. package/modules/hall-ui/public/diagram-viewer.css +51 -34
  7. package/modules/hall-ui/public/diagram-viewer.js +4 -1
  8. package/modules/hall-ui/public/diagrams.css +45 -0
  9. package/modules/hall-ui/public/diagrams.html +12 -20
  10. package/modules/hall-ui/public/diagrams.states.json +28 -0
  11. package/modules/hall-ui/public/idea.css +138 -71
  12. package/modules/hall-ui/public/idea.html +13 -3
  13. package/modules/hall-ui/public/idea.js +17 -4
  14. package/modules/hall-ui/public/idea.states.json +14 -0
  15. package/modules/hall-ui/public/ideas.css +148 -107
  16. package/modules/hall-ui/public/ideas.html +15 -5
  17. package/modules/hall-ui/public/ideas.states.json +15 -0
  18. package/modules/hall-ui/public/primer.css +92 -400
  19. package/modules/hall-ui/public/primer.html +68 -26
  20. package/modules/hall-ui/public/primer.js +107 -308
  21. package/modules/hall-ui/public/primer.states.json +38 -0
  22. package/modules/hall-ui/public/ranks.html +9 -1
  23. package/modules/hall-ui/public/ranks.states.json +1 -1
  24. package/modules/hall-ui/public/record.css +324 -0
  25. package/modules/hall-ui/public/roadmap.css +152 -86
  26. package/modules/hall-ui/public/roadmap.html +6 -1
  27. package/modules/hall-ui/public/roadmap.states.json +31 -0
  28. package/modules/hall-ui/public/room.css +441 -0
  29. package/modules/hall-ui/public/style.css +269 -63
  30. package/modules/hall-ui/public/task.css +71 -0
  31. package/modules/hall-ui/public/task.html +15 -32
  32. package/modules/hall-ui/public/task.js +142 -39
  33. package/modules/hall-ui/public/task.states.json +14 -0
  34. package/modules/hall-ui/public/work.css +4 -15
  35. package/modules/ui-design/kit/serve.js +7 -1
  36. package/package-lock.json +2 -2
  37. package/package.json +1 -1
  38. package/scripts/hall-preview/server.js +34 -0
  39. package/src/module-api.js +1 -1
  40. package/tests/hall_audit.mjs +18 -11
  41. package/tests/hall_reading_world.mjs +430 -0
  42. package/tests/hall_record_world.mjs +412 -0
@@ -0,0 +1,441 @@
1
+ /* room.css — the READING-ROOM archetype: a long document read end to end
2
+ (task 1003306, goal 1000081). Shared by the primer (primer.html) and the
3
+ diagrams index (diagrams.html).
4
+
5
+ THE ARCHETYPE is v3 "the glass hall", the owner's pick from the composition
6
+ round — docs/design/hall-direction-v2.md §6, mock
7
+ docs/design/mocks/hall/reading/v3.html. Reading order, top to bottom: a
8
+ progress hairline under the topbar; the room's name alone over the ground
9
+ (the shell's .page-head--room); then a GLASS table of contents beside a
10
+ --bg-card article card. The glass/card split is the composition's argument:
11
+ wayfinding is chrome and belongs to the same material as the rail and the
12
+ topbar, the document is content and belongs on a panel the ground can never
13
+ reach the ink on.
14
+
15
+ WHY IT IS ITS OWN SHEET rather than more of primer.css: the primer and the
16
+ diagrams index are the same room over different documents — one renders
17
+ markdown, one renders five figures — and the framed figure is literally the
18
+ same object on both (diagram-viewer.js upgrades `figure.diagram img,
19
+ figure.primer-figure img` with one selector). Ranks, Economy, Repo Atlas and
20
+ Modules inherit this archetype next. Page-specific shapes stay page-local:
21
+ primer.css keeps the acknowledge gate, diagrams.css keeps the legend strip.
22
+
23
+ WHY THE CLASSES ARE STILL `primer-`: two live surfaces spell them —
24
+ diagram-viewer.js's upgrade selector and tests/hall_audit.mjs's pinned
25
+ phone-overflow rule — so the sheet is named for the ROOM and the prefix is
26
+ left alone. Renaming would churn a JS selector and a pinned test to buy a
27
+ reader nothing.
28
+
29
+ THE PANEL IS THE SHELL'S. The article, the failure notes and the skeleton all
30
+ carry `.scroll` in their markup and this sheet only adds the reading padding:
31
+ v3 has exactly three card levels and a fourth is a design decision, not a
32
+ local override (modules/hall-ui/CLAUDE.md, Hard rules).
33
+
34
+ Everything below spends the world's real token names. No compat alias
35
+ (--surface / --surface-2 / --border / --border-strong / --accent-weak /
36
+ --accent-text) appears here — they exist for pages nobody has re-skinned, so
37
+ spending one is legal CSS that quietly opts this sheet back out of the world.
38
+ `--line` is a WIDTH; the hairline's colour is --rule / --rule-soft. */
39
+
40
+ /* ---- the room's composition tokens ---------------------------------------
41
+ On `body`, never in a page `:root`: the branding pack's :root is spliced at
42
+ the end of <head> at (0,1,0), so a page-local one is outranked one way and
43
+ defeats re-branding the other.
44
+ --measure is NOT redeclared. It is the shell's measured 48ch, and a `ch`
45
+ scales with the font size — so the same token renders the same ~60 characters
46
+ whether the room reads at 15px or 17px. Re-deriving it per page size is the
47
+ `ch` arithmetic that put 90 characters on this page in the first place. */
48
+ body.room {
49
+ --room-gap: var(--sp-lg);
50
+ --room-toc-w: 246px;
51
+ --room-pad: clamp(24px, 3.4vw, 58px);
52
+ --room-size: 17px;
53
+ --room-lead: 1.75;
54
+ --room-h2: clamp(24px, 2.8vw, 34px);
55
+ --room-h3: 20px;
56
+ }
57
+
58
+ /* ---- 1. the reading hairline --------------------------------------------
59
+ Sticky rather than fixed: it belongs to the content column, so it scrolls out
60
+ of the way with the head instead of hovering over the whole viewport. Under
61
+ the topbar in the z ladder (--z-progress < --z-topbar) for the same reason —
62
+ it is the article's progress, not app chrome. */
63
+ .primer-progress {
64
+ position: sticky;
65
+ top: var(--topbar-h);
66
+ z-index: var(--z-progress);
67
+ height: 3px;
68
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
69
+ pointer-events: none;
70
+ }
71
+ .primer-progress__bar {
72
+ height: 100%;
73
+ width: 0;
74
+ background: var(--accent);
75
+ transition: width 200ms cubic-bezier(.2, .7, .3, 1);
76
+ }
77
+
78
+ /* ---- 2. the reading column ----------------------------------------------
79
+ ONE ceiling for the room, on the room's own body scope. --content-max (1120)
80
+ is a working surface's width; a document read at it is more empty ground than
81
+ page. The cap sits on the room's main rather than on each page's wrapper so
82
+ the primer's two columns and the diagrams index's stacked figures end at the
83
+ same edge — a reading room that changes width between its own pages reads as
84
+ two different rooms.
85
+ This is the room's own composition, not a shell override: it is scoped to the
86
+ body class a page opts into, and it sets a measure, not shell layout (the
87
+ rule tests/hall_record_world.mjs pins is `.app-content > main`, which reaches
88
+ into the shell's grid for every page at once). */
89
+ body.room #hall-main,
90
+ body.room .page-head { max-width: var(--room-max); }
91
+
92
+ .primer-layout {
93
+ display: grid;
94
+ grid-template-columns: var(--room-toc-w) minmax(0, 1fr);
95
+ gap: var(--room-gap);
96
+ align-items: start;
97
+ padding-bottom: var(--sp-md);
98
+ }
99
+ /* the article column, so the notes, the skeleton and the gate stack under the
100
+ card rather than beside the contents */
101
+ .primer-col { min-width: 0; }
102
+
103
+ /* ---- 3. the table of contents, as glass ---------------------------------- */
104
+
105
+ .primer-toc {
106
+ position: sticky;
107
+ top: calc(var(--topbar-h) + var(--sp-md));
108
+ align-self: start;
109
+ }
110
+ .primer-toc__toggle {
111
+ display: none;
112
+ width: 100%;
113
+ align-items: center;
114
+ justify-content: space-between;
115
+ gap: 8px;
116
+ min-height: 44px;
117
+ padding: 8px 16px;
118
+ background: var(--glass);
119
+ -webkit-backdrop-filter: blur(var(--glass-blur));
120
+ backdrop-filter: blur(var(--glass-blur));
121
+ border: var(--line) solid var(--glass-edge);
122
+ border-radius: var(--radius);
123
+ font-family: var(--font-body);
124
+ font-size: 14.5px;
125
+ color: var(--ink);
126
+ cursor: pointer;
127
+ }
128
+ .primer-toc__chevron { transition: transform 200ms cubic-bezier(.2, .7, .3, 1); }
129
+ .primer-toc__toggle[aria-expanded="true"] .primer-toc__chevron { transform: rotate(180deg); }
130
+ .primer-toc__inner {
131
+ background: var(--glass);
132
+ -webkit-backdrop-filter: blur(var(--glass-blur));
133
+ backdrop-filter: blur(var(--glass-blur));
134
+ border: var(--line) solid var(--glass-edge);
135
+ border-radius: var(--radius);
136
+ padding: var(--sp-md) var(--sp-sm) var(--sp-sm);
137
+ }
138
+ .primer-toc__heading {
139
+ margin: 0 0 var(--sp-sm);
140
+ padding: 0 var(--sp-xs);
141
+ font-family: var(--label-face);
142
+ font-size: var(--label-size);
143
+ font-weight: 400;
144
+ letter-spacing: var(--label-space);
145
+ text-transform: var(--label-case);
146
+ color: var(--ink-faint);
147
+ }
148
+ .primer-toc__list { list-style: none; margin: 0; padding: 0; counter-reset: toc; }
149
+ .primer-toc__list li { margin: 0; }
150
+ /* the numeral is a two-digit mono column, so a long list never re-spaces around
151
+ its tenth row the way an upper-roman VIII did */
152
+ .primer-toc__list a {
153
+ display: flex;
154
+ align-items: baseline;
155
+ gap: 11px;
156
+ min-height: 34px;
157
+ padding: 8px var(--sp-xs);
158
+ border-left: 2px solid transparent;
159
+ border-radius: var(--radius-sm);
160
+ font-size: 14px;
161
+ line-height: 1.4;
162
+ color: var(--ink-soft);
163
+ text-decoration: none;
164
+ transition: color 200ms cubic-bezier(.2, .7, .3, 1);
165
+ }
166
+ .primer-toc__list a::before {
167
+ counter-increment: toc;
168
+ content: counter(toc, decimal-leading-zero);
169
+ flex: none;
170
+ font: 400 11px/1.4 var(--font-mono);
171
+ font-variant-numeric: tabular-nums;
172
+ color: var(--ink-faint);
173
+ }
174
+ .primer-toc__list a:hover { color: var(--ink); text-decoration: none; }
175
+ .primer-toc__list a.is-active {
176
+ color: var(--ink);
177
+ background: var(--glass-strong);
178
+ border-left-color: var(--accent);
179
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
180
+ }
181
+ .primer-toc__list a.is-active::before { color: var(--ink-soft); }
182
+ .primer-toc__placeholder {
183
+ padding: 8px var(--sp-xs);
184
+ font-size: 14px;
185
+ color: var(--ink-faint);
186
+ }
187
+
188
+ /* ---- 4. the article ------------------------------------------------------
189
+ The card itself is `.scroll`; this is the reading pad and the rhythm. */
190
+
191
+ .primer-article {
192
+ padding: var(--room-pad);
193
+ margin: 0;
194
+ counter-reset: sec;
195
+ font-size: var(--room-size);
196
+ line-height: var(--room-lead);
197
+ color: var(--ink);
198
+ }
199
+ /* PROSE is measured; a table, a figure and a code block may take the whole card,
200
+ and that width is the only reason the card is wider than the measure. */
201
+ .primer-article > p,
202
+ .primer-article > ul,
203
+ .primer-article > ol,
204
+ .primer-article > blockquote,
205
+ .primer-article > h2,
206
+ .primer-article > h3 { max-width: var(--measure); }
207
+
208
+ /* the document's own h1 is suppressed — the page head already names the room,
209
+ and a second h1 in <main> fails the one-header-main-h1 floor outright */
210
+ .primer-article h1 { display: none; }
211
+
212
+ .primer-article h2 {
213
+ margin: calc(var(--sp-xl) * 1.4) 0 var(--sp-md);
214
+ font-family: var(--font-display);
215
+ font-weight: 300;
216
+ font-size: var(--room-h2);
217
+ line-height: 1.06;
218
+ letter-spacing: -0.035em;
219
+ color: var(--ink);
220
+ /* anchor jumps land below the sticky top bar AND its hairline */
221
+ scroll-margin-top: calc(var(--topbar-h) + 28px);
222
+ }
223
+ /* the section number sits above the headline rather than beside it, so a long
224
+ title stays one uninterrupted shape at every width */
225
+ .primer-article h2::before {
226
+ counter-increment: sec;
227
+ content: counter(sec, decimal-leading-zero);
228
+ display: block;
229
+ margin-bottom: 14px;
230
+ font-family: var(--label-face);
231
+ font-size: var(--label-size);
232
+ letter-spacing: var(--label-space);
233
+ font-variant-numeric: tabular-nums;
234
+ color: var(--ink-faint);
235
+ }
236
+ .primer-article > h2:first-child { margin-top: 0; }
237
+ .primer-article h3 {
238
+ margin: var(--sp-lg) 0 var(--sp-xs);
239
+ font-family: var(--font-display);
240
+ font-weight: 400;
241
+ font-size: var(--room-h3);
242
+ letter-spacing: -0.02em;
243
+ color: var(--ink);
244
+ scroll-margin-top: calc(var(--topbar-h) + 28px);
245
+ }
246
+
247
+ .primer-article p { margin: 0 0 var(--sp-md); }
248
+ .primer-article p:last-child { margin-bottom: 0; }
249
+ /* the subtitle line at the very top of the document */
250
+ .primer-article > p > em:only-child { color: var(--ink-soft); }
251
+
252
+ .primer-article ul, .primer-article ol { margin: 0 0 var(--sp-lg); padding-left: 1.4em; }
253
+ .primer-article li { margin: 0 0 12px; }
254
+ .primer-article li:last-child { margin-bottom: 0; }
255
+ .primer-article li::marker { color: var(--ink-faint); }
256
+
257
+ /* 1px of vertical padding takes an inline link past the 24px floor without
258
+ costing the line its own leading (the .scroll__lede precedent, task 1003304) */
259
+ .primer-article a {
260
+ display: inline-block;
261
+ min-height: 24px;
262
+ padding: 1px 0;
263
+ color: var(--accent-ink);
264
+ text-decoration: underline;
265
+ text-underline-offset: 4px;
266
+ text-decoration-thickness: 1px;
267
+ }
268
+ .primer-article a:hover { color: var(--ink); }
269
+ .primer-article strong { font-weight: 600; color: var(--ink); }
270
+ .primer-article em { font-style: italic; }
271
+
272
+ .primer-article code {
273
+ font: 400 .85em/1.4 var(--font-mono);
274
+ background: var(--glass);
275
+ padding: 2px 6px;
276
+ border-radius: 4px;
277
+ }
278
+ .primer-article pre {
279
+ margin: 0 0 var(--sp-lg);
280
+ padding: var(--sp-md) var(--sp-lg);
281
+ overflow-x: auto;
282
+ background: var(--glass);
283
+ border: var(--line) solid var(--glass-edge);
284
+ border-radius: var(--radius);
285
+ }
286
+ .primer-article pre code {
287
+ background: none;
288
+ padding: 0;
289
+ border-radius: 0;
290
+ font-size: 13.5px;
291
+ line-height: 1.8;
292
+ color: var(--ink-soft);
293
+ }
294
+
295
+ /* blockquotes only render since task 1003306 unified the two markdown parsers —
296
+ primer.js had no blockquote rule at all and md-reader.js has always emitted
297
+ them, so the primer silently dropped every aside into a paragraph. */
298
+ .primer-article blockquote {
299
+ margin: var(--sp-lg) 0;
300
+ padding: var(--sp-md) var(--sp-lg);
301
+ background: var(--glass);
302
+ border: var(--line) solid var(--glass-edge);
303
+ border-left: 2px solid var(--rule);
304
+ border-radius: 0 var(--radius) var(--radius) 0;
305
+ color: var(--ink-soft);
306
+ }
307
+ .primer-article blockquote p { margin: 0; max-width: var(--measure); }
308
+
309
+ .primer-article hr {
310
+ border: none;
311
+ border-top: var(--line) solid var(--rule-soft);
312
+ margin: var(--sp-xl) 0;
313
+ }
314
+
315
+ .primer-article table {
316
+ width: 100%;
317
+ border-collapse: collapse;
318
+ margin: 0 0 var(--sp-lg);
319
+ font-size: 14.5px;
320
+ font-variant-numeric: tabular-nums;
321
+ }
322
+ .primer-article th, .primer-article td {
323
+ text-align: left;
324
+ vertical-align: top;
325
+ padding: 13px 16px 13px 0;
326
+ border-bottom: var(--line) solid var(--rule-soft);
327
+ }
328
+ .primer-article th {
329
+ font-family: var(--label-face);
330
+ font-size: var(--label-size);
331
+ font-weight: 400;
332
+ letter-spacing: var(--label-space);
333
+ text-transform: var(--label-case);
334
+ color: var(--ink-faint);
335
+ }
336
+ .primer-article tr:last-child td { border-bottom: 0; }
337
+
338
+ /* ---- 5. the framed figure ------------------------------------------------
339
+ ONE rule, both rooms: diagram-viewer.js upgrades `figure.diagram img,
340
+ figure.primer-figure img` into a pannable canvas, and until (or unless) the
341
+ SVG fetch succeeds the PNG stays in this frame. Glass rather than a card, so
342
+ a figure inside the article reads as inset and a figure on the diagrams index
343
+ reads as the same object. */
344
+ .primer-figure, figure.diagram {
345
+ margin: var(--sp-xl) 0;
346
+ padding: var(--sp-lg) var(--sp-md);
347
+ background: var(--glass);
348
+ border: var(--line) solid var(--glass-edge);
349
+ border-radius: var(--radius);
350
+ }
351
+ .primer-figure:last-child, figure.diagram:last-child { margin-bottom: 0; }
352
+ .primer-figure img, figure.diagram img {
353
+ display: block;
354
+ width: 100%;
355
+ max-width: 100%;
356
+ height: auto;
357
+ }
358
+ /* diagram-viewer.js inserts its canvas INSIDE the figure and hides the <img>,
359
+ so the frame has to belong to exactly one of them or the diagram ends up in
360
+ two nested boxes. The figure keeps it; the canvas gives its own up. (Its
361
+ fullscreen state re-declares both, and diagram-viewer.css loads after this
362
+ sheet on both pages, so the overlay still paints.) */
363
+ .primer-figure .dgv, figure.diagram .dgv {
364
+ background: none;
365
+ border: 0;
366
+ border-radius: var(--radius-sm);
367
+ }
368
+ .primer-figure figcaption, figure.diagram figcaption {
369
+ margin-top: 14px;
370
+ max-width: var(--measure);
371
+ font-size: 13.5px;
372
+ line-height: 1.55;
373
+ color: var(--ink-faint);
374
+ }
375
+
376
+ /* ---- 6. the states before the document ----------------------------------
377
+ Each is the same card the article is, so the page never changes shape as it
378
+ resolves — the skeleton is the article's silhouette, not a spinner. */
379
+
380
+ .primer-note, .primer-skeleton { padding: var(--room-pad); }
381
+ .primer-note__label {
382
+ margin: 0 0 14px;
383
+ font-family: var(--label-face);
384
+ font-size: var(--label-size);
385
+ letter-spacing: var(--label-space);
386
+ text-transform: var(--label-case);
387
+ color: var(--ink-faint);
388
+ }
389
+ .primer-note--error .primer-note__label { color: var(--danger); }
390
+ .primer-note__body { margin: 0 0 var(--sp-lg); max-width: var(--measure); color: var(--ink-soft); }
391
+ .primer-note__body:last-child { margin-bottom: 0; }
392
+ .primer-note__acts { display: flex; flex-wrap: wrap; gap: var(--sp-xs); margin: 0; }
393
+
394
+ .primer-sk {
395
+ display: block;
396
+ height: 10px;
397
+ border-radius: 4px;
398
+ background: var(--skeleton);
399
+ }
400
+ .primer-skeleton__h { height: 28px; width: 58%; margin-bottom: var(--sp-lg); }
401
+ .primer-skeleton__p { margin-bottom: var(--sp-lg); max-width: var(--measure); }
402
+ .primer-skeleton__p .primer-sk { margin-bottom: 15px; }
403
+ .primer-skeleton__p .primer-sk:nth-child(2) { width: 96%; }
404
+ .primer-skeleton__p .primer-sk:nth-child(3) { width: 99%; }
405
+ .primer-skeleton__p .primer-sk:nth-child(4) { width: 84%; }
406
+ .primer-skeleton__p .primer-sk:last-child { width: 46%; margin-bottom: 0; }
407
+ .primer-skeleton__rule {
408
+ height: var(--line);
409
+ margin: var(--sp-xl) 0 var(--sp-lg);
410
+ background: var(--rule-soft);
411
+ }
412
+
413
+ /* ---- 7. the room's one breakpoint ---------------------------------------
414
+ 760px, NOT the shell's 640: it is the width primer.js's matchMedia mirrors
415
+ and tests/hall_audit.mjs pins exactly. Narrowing it "for consistency" would
416
+ silently reopen the 641-760px band the table's scrollport exists to cover. */
417
+ @media (max-width: 760px) {
418
+ body.room {
419
+ --room-gap: 0px;
420
+ --room-pad: 20px;
421
+ --room-size: 16.5px;
422
+ --room-lead: 1.7;
423
+ --room-h2: 24px;
424
+ }
425
+ .primer-layout { grid-template-columns: minmax(0, 1fr); }
426
+ .primer-toc { position: static; margin-bottom: var(--sp-sm); }
427
+ .primer-toc__toggle { display: flex; }
428
+ .primer-toc__inner { display: none; margin-top: 8px; }
429
+ .primer-toc.is-open .primer-toc__inner { display: block; }
430
+ /* A markdown table's column count is fixed by its source, so its min-content
431
+ width outruns a phone (measured: 79px of page overflow on /drachmae). Give
432
+ the table its own horizontal scroller instead of letting it drag the page
433
+ sideways. `display: block` is what makes the table box a scrollport; the
434
+ rows still lay out through the anonymous table box inside it. */
435
+ .primer-article table {
436
+ display: block;
437
+ width: max-content;
438
+ max-width: 100%;
439
+ overflow-x: auto;
440
+ }
441
+ }