@bongos/core 1.19.455 → 1.19.456

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 (48) hide show
  1. package/.bongos-core.json +106 -41
  2. package/docs/copy-inventory.md +231 -228
  3. package/docs/copy-registry.json +352 -312
  4. package/docs/module-api-changelog.md +2 -0
  5. package/modules/hall-ui/public/atlas.css +41 -32
  6. package/modules/hall-ui/public/atlas.html +8 -0
  7. package/modules/hall-ui/public/atlas.states.json +60 -0
  8. package/modules/hall-ui/public/collab.css +2 -2
  9. package/modules/hall-ui/public/collab.html +7 -1
  10. package/modules/hall-ui/public/collab.states.json +60 -0
  11. package/modules/hall-ui/public/copy-desk.css +21 -16
  12. package/modules/hall-ui/public/copy-desk.html +9 -1
  13. package/modules/hall-ui/public/copy-desk.states.json +59 -0
  14. package/modules/hall-ui/public/drachmae.html +38 -5
  15. package/modules/hall-ui/public/drachmae.js +20 -2
  16. package/modules/hall-ui/public/drachmae.states.json +64 -0
  17. package/modules/hall-ui/public/gate.css +20 -25
  18. package/modules/hall-ui/public/gate.html +9 -1
  19. package/modules/hall-ui/public/gate.states.json +60 -0
  20. package/modules/hall-ui/public/goals-lib.js +22 -5
  21. package/modules/hall-ui/public/goals-render.js +27 -5
  22. package/modules/hall-ui/public/goals.css +141 -60
  23. package/modules/hall-ui/public/goals.html +8 -1
  24. package/modules/hall-ui/public/goals.states.json +74 -0
  25. package/modules/hall-ui/public/government.css +35 -36
  26. package/modules/hall-ui/public/government.html +9 -1
  27. package/modules/hall-ui/public/government.states.json +59 -0
  28. package/modules/hall-ui/public/harbor.css +23 -26
  29. package/modules/hall-ui/public/harbor.html +9 -1
  30. package/modules/hall-ui/public/harbor.states.json +59 -0
  31. package/modules/hall-ui/public/modules.css +22 -21
  32. package/modules/hall-ui/public/modules.html +9 -1
  33. package/modules/hall-ui/public/modules.states.json +73 -0
  34. package/modules/hall-ui/public/people.html +7 -1
  35. package/modules/hall-ui/public/people.states.json +59 -0
  36. package/modules/hall-ui/public/scouting.html +7 -1
  37. package/modules/hall-ui/public/scouting.states.json +54 -0
  38. package/modules/hall-ui/public/sessions.css +1 -1
  39. package/modules/hall-ui/public/sessions.html +9 -1
  40. package/modules/hall-ui/public/sessions.states.json +58 -0
  41. package/modules/hall-ui/public/style.css +125 -5
  42. package/modules/hall-ui/public/watch.css +36 -39
  43. package/modules/hall-ui/public/watch.html +9 -1
  44. package/modules/hall-ui/public/watch.states.json +60 -0
  45. package/package-lock.json +2 -2
  46. package/package.json +1 -1
  47. package/src/module-api.js +1 -1
  48. package/tests/goal_subtitle.mjs +14 -8
@@ -1347,5 +1347,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
1347
1347
  landed since 1.19.453 with no explicit bump. run 33554965618. (task 1002620)
1348
1348
  1.19.455 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1349
1349
  landed since 1.19.454 with no explicit bump. run 33558738299. (task 1002620)
1350
+ 1.19.456 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1351
+ landed since 1.19.455 with no explicit bump. run 33560584235. (task 1002620)
1350
1352
  ---------------------------------------------------------------------------
1351
1353
  ```
@@ -13,40 +13,49 @@
13
13
  renderer reads at draw time, with dark variants, so the scene adapts to
14
14
  the theme without the pack touching the encoding. */
15
15
  .atlas-page{
16
- /* semantic map palette — FIXED (never pack-driven), tuned for both themes */
16
+ /* THE SEMANTIC MAP PALETTE — the sanctioned exception, alongside the shell's
17
+ status vocabulary. ADR 0094's invariant is that a pack's colours must never
18
+ scramble the map's colour-coded MEANING, so these nine are fixed literals on
19
+ purpose and are not the Fifteen Rule's business. Everything BELOW them is
20
+ chrome, and chrome is the world's (task 1003307). */
17
21
  --ab-sun:#6366f1; --ab-sky:#0ea5e9; --ab-coral:#f43f5e; --ab-paper:#b3a284;
18
22
  --ab-good:#10b981; --ab-core:#f59e0b; --ab-db:#ef4444; --ab-ghost:#94a3b8; --ab-danger:#dc2626;
19
23
  /* theme-dependent, non-semantic scene values (read by atlas.js) */
20
24
  --ab-label-ink: var(--ink);
21
- --ab-label-halo: var(--surface);
25
+ --ab-label-halo: var(--bg-card);
26
+ /* Pure white with alpha as an ambient wash — the Fifteen Rule's one legal
27
+ literal shape (a scrim, a mask or a halo). */
22
28
  --ab-ambient: rgba(255,255,255,.5);
23
- --ab-glow: #c7cdf7;
24
- --ab-b-good-bg:#dcfce7; --ab-b-good-fg:#166534;
25
- --ab-b-warn-bg:#fef3c7; --ab-b-warn-fg:#92400e;
26
- --ab-b-danger-bg:#fee2e2; --ab-b-danger-fg:#991b1b;
27
- --ab-b-info-bg:#e0f2fe; --ab-b-info-fg:#075985;
29
+ /* Was #c7cdf7 / #3b418c, a private periwinkle nobody could re-theme. The world
30
+ already holds a second hue for exactly this: --sea, which the hall otherwise
31
+ never spends. */
32
+ --ab-glow: color-mix(in srgb, var(--sea) 30%, var(--bg-card));
33
+ /* The badge fills were eight literals plus eight dark twins. They are the
34
+ four-state vocabulary the shell already measures on both grounds in both
35
+ modes (tests/hall_tokens.mjs), so they are that vocabulary now — which is
36
+ also why this rule needs no dark block for them any more. */
37
+ --ab-b-good-bg:var(--ok-weak); --ab-b-good-fg:var(--ok);
38
+ --ab-b-warn-bg:var(--warn-weak); --ab-b-warn-fg:var(--warn);
39
+ --ab-b-danger-bg:var(--danger-weak); --ab-b-danger-fg:var(--danger);
40
+ --ab-b-info-bg:var(--info-weak); --ab-b-info-fg:var(--info);
28
41
  color:var(--ink);
29
- border:1px solid var(--border); border-radius:var(--radius);
42
+ border:var(--line) solid var(--rule-soft); border-radius:var(--radius);
30
43
  background:
31
44
  radial-gradient(ellipse 70% 55% at 50% 46%, color-mix(in srgb, var(--accent) 4%, transparent), transparent 70%),
32
- var(--surface);
45
+ var(--bg-card);
33
46
  }
47
+ /* The dark twin, still written twice and still byte-identical — that rule does
48
+ not bend. What shrank is what it has to SAY: the badge pairs flip themselves
49
+ now that they are the status vocabulary, so only the two genuinely scene-level
50
+ values are left (task 1003307). */
34
51
  html[data-theme="dark"] .atlas-page{
35
52
  --ab-ambient: rgba(255,255,255,.03);
36
- --ab-glow: #3b418c;
37
- --ab-b-good-bg:#123227; --ab-b-good-fg:#5eead4;
38
- --ab-b-warn-bg:#33260d; --ab-b-warn-fg:#fcd34d;
39
- --ab-b-danger-bg:#371616; --ab-b-danger-fg:#fca5a5;
40
- --ab-b-info-bg:#0f2740; --ab-b-info-fg:#7dd3fc;
53
+ --ab-glow: color-mix(in srgb, var(--sea) 55%, var(--bg));
41
54
  }
42
55
  @media (prefers-color-scheme: dark){
43
56
  html:not([data-theme]) .atlas-page{
44
57
  --ab-ambient: rgba(255,255,255,.03);
45
- --ab-glow: #3b418c;
46
- --ab-b-good-bg:#123227; --ab-b-good-fg:#5eead4;
47
- --ab-b-warn-bg:#33260d; --ab-b-warn-fg:#fcd34d;
48
- --ab-b-danger-bg:#371616; --ab-b-danger-fg:#fca5a5;
49
- --ab-b-info-bg:#0f2740; --ab-b-info-fg:#7dd3fc;
58
+ --ab-glow: color-mix(in srgb, var(--sea) 55%, var(--bg));
50
59
  }
51
60
  }
52
61
  .atlas-page *{box-sizing:border-box}
@@ -54,12 +63,12 @@ html[data-theme="dark"] .atlas-page{
54
63
 
55
64
  .atlas-toolbar{display:flex; align-items:center; gap:12px 16px; flex-wrap:wrap; padding:16px 20px 0}
56
65
  .ab-chip{font-weight:600; font-size:10.5px; text-transform:uppercase; letter-spacing:.1em;
57
- color:var(--accent-text); background:var(--accent-weak); border:1px solid color-mix(in srgb, var(--accent) 30%, transparent); padding:3px 9px; border-radius:999px}
58
- .ab-modes{display:inline-flex; gap:0; border:1px solid var(--border-strong); border-radius:var(--radius-sm); overflow:hidden}
66
+ color:var(--accent-ink); background:var(--accent-tint); border:var(--line) solid color-mix(in srgb, var(--accent) 30%, transparent); padding:3px 9px; border-radius: var(--radius-pill)}
67
+ .ab-modes{display:inline-flex; gap:0; border:var(--line) solid var(--rule); border-radius:var(--radius-sm); overflow:hidden}
59
68
  .ab-modes button{font-family:var(--font-body); font-weight:500; font-size:12.5px; cursor:pointer; border:0;
60
- background:var(--surface); color:var(--ink-soft); padding:6px 14px; transition:background .15s, color .15s}
61
- .ab-modes button + button{border-left:1px solid var(--border-strong)}
62
- .ab-modes button.active{background:var(--accent-weak); color:var(--accent-text)}
69
+ background:var(--bg-card); color:var(--ink-soft); padding:6px 14px; transition:background .15s, color .15s}
70
+ .ab-modes button + button{border-left:var(--line) solid var(--rule)}
71
+ .ab-modes button.active{background:var(--accent-tint); color:var(--accent-ink)}
63
72
  .ab-modes button:focus-visible{outline:2px solid var(--accent); outline-offset:-2px}
64
73
 
65
74
  .ab-caption{padding:13px 20px 0; margin:0; font-size:13px; line-height:1.5; color:var(--ink-soft); max-width:90ch}
@@ -68,10 +77,10 @@ html[data-theme="dark"] .atlas-page{
68
77
  .ab-scene{position:relative; width:100%; min-height:500px; padding:6px 0}
69
78
  .ab-scene svg{display:block; width:100%; height:auto}
70
79
  .ab-hint{position:absolute; left:20px; bottom:12px; font-size:11.5px; color:var(--ink-soft);
71
- background:color-mix(in srgb, var(--surface) 75%, transparent); backdrop-filter:blur(4px); padding:5px 11px; border-radius:999px; border:1px solid var(--border)}
80
+ background:color-mix(in srgb, var(--bg-card) 75%, transparent); backdrop-filter:blur(4px); padding:5px 11px; border-radius: var(--radius-pill); border:var(--line) solid var(--rule-soft)}
72
81
  .ab-empty{position:absolute; inset:0; display:none; align-items:center; justify-content:center; text-align:center; padding:40px}
73
82
  .ab-empty.show{display:flex}
74
- .ab-empty .card{background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:26px 30px; max-width:460px;
83
+ .ab-empty .card{background:var(--bg-card); border:var(--line) solid var(--rule-soft); border-radius:var(--radius); padding:26px 30px; max-width:460px;
75
84
  box-shadow:var(--shadow-pop)}
76
85
  .ab-empty h2{margin:0 0 8px; font-size:16px; font-weight:650}
77
86
  .ab-empty p{margin:0; font-size:13.5px; line-height:1.55; color:var(--ink-soft)}
@@ -82,8 +91,8 @@ html[data-theme="dark"] .atlas-page{
82
91
  .ab-legend .ln{width:18px; border-top:3px solid}
83
92
  .ab-foot{padding:10px 20px 20px; font-size:11px; color:var(--ink-faint); font-variant-numeric:tabular-nums}
84
93
 
85
- .ab-popup{position:absolute; z-index:6; width:300px; max-width:88%; background:var(--surface);
86
- border:1px solid var(--border); border-radius:var(--radius); padding:15px 16px; display:none;
94
+ .ab-popup{position:absolute; z-index:6; width:300px; max-width:88%; background:var(--bg-card);
95
+ border:var(--line) solid var(--rule-soft); border-radius:var(--radius); padding:15px 16px; display:none;
87
96
  box-shadow:var(--shadow-pop)}
88
97
  .ab-popup.show{display:block}
89
98
  .ab-popup-close{position:absolute; top:8px; right:11px; cursor:pointer; border:0; background:transparent;
@@ -91,13 +100,13 @@ html[data-theme="dark"] .atlas-page{
91
100
  .ab-popup-close:hover{color:var(--ink)}
92
101
  .ab-ptitle{font-weight:650; font-size:15px; display:flex; align-items:center;
93
102
  gap:8px; flex-wrap:wrap; line-height:1.25; padding-right:18px}
94
- .ab-ppath{font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace; font-size:11.5px; color:var(--ink-soft); margin-top:4px; word-break:break-all}
103
+ .ab-ppath{font-family: var(--font-mono); font-size:11.5px; color:var(--ink-soft); margin-top:4px; word-break:break-all}
95
104
  .ab-pdesc{font-size:12.8px; line-height:1.55; margin:11px 0 0; color:var(--ink-soft)}
96
105
  .ab-prow{margin-top:11px; font-size:10.5px; font-weight:600; color:var(--ink-faint); text-transform:uppercase; letter-spacing:.06em}
97
106
  .ab-chips{display:flex; flex-wrap:wrap; gap:6px; margin-top:6px}
98
- .ab-chip2{font-size:11px; font-weight:500; background:var(--surface-2); border:1px solid var(--border);
99
- padding:4px 9px; border-radius:999px; font-variant-numeric:tabular-nums}
100
- .ab-badge{font-weight:600; font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; padding:3px 8px; border-radius:999px}
107
+ .ab-chip2{font-size:11px; font-weight:500; background:var(--glass); border:var(--line) solid var(--rule-soft);
108
+ padding:4px 9px; border-radius: var(--radius-pill); font-variant-numeric:tabular-nums}
109
+ .ab-badge{font-weight:600; font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; padding:3px 8px; border-radius: var(--radius-pill)}
101
110
  .ab-b-good{background:var(--ab-b-good-bg); color:var(--ab-b-good-fg)} .ab-b-warn{background:var(--ab-b-warn-bg); color:var(--ab-b-warn-fg)}
102
111
  .ab-b-danger{background:var(--ab-b-danger-bg); color:var(--ab-b-danger-fg)} .ab-b-info{background:var(--ab-b-info-bg); color:var(--ab-b-info-fg)}
103
112
 
@@ -19,6 +19,14 @@
19
19
  <div class="app-body">
20
20
  <header class="app-topbar" id="app-topbar"></header>
21
21
  <div class="app-content">
22
+ <!-- task 1003307: the atlas shipped with no page head and no <h1> — the
23
+ map filled the column and the page had no name in the document. The
24
+ board's label voice gives it one without competing with the map. -->
25
+ <div class="page-head page-head--board">
26
+ <h1 class="page-head__h">Repo atlas</h1>
27
+ <p class="page-head__sub">A self-drawing map of the codebase: what each module is, and what depends on it.</p>
28
+ </div>
29
+
22
30
  <main id="hall-main">
23
31
  <!-- The atlas chrome rides the hall tokens (pack + dark aware, task 1737);
24
32
  only the semantic node/edge palette stays instance-independent so a
@@ -0,0 +1,60 @@
1
+ {
2
+ "_": "Repo atlas — the self-drawing module map. Its SEMANTIC node palette is fixed by ADR 0094 and is not the token tier's business; everything around it (toolbar, chips, legend, popup, badges) is chrome and rides the world. Written with the re-skin (task 1003307) so this page is MEASURED at three widths in both modes rather than looked at once.",
3
+ "page": "/builders/atlas",
4
+ "surface": "hall-ui",
5
+ "stub": {
6
+ "prefix": "/builders/"
7
+ },
8
+ "modeQuery": false,
9
+ "_feeds": "The kit's own stub carries no feed for this page, so against it the page renders its EMPTY and SKELETON states — which is the point: those are states the floors must hold in. Against the hall-preview harness the same states render populated. Every declared 404 below is a fixture the harness does not carry, named rather than hidden.",
10
+ "ignoreRequests": [
11
+ "/api/(gds|bongos)/me$",
12
+ "/api/(gds|bongos)/me/",
13
+ "/api/(gds|bongos)/goals",
14
+ "/api/(gds|bongos)/inbox/",
15
+ "/api/(gds|bongos)/versions",
16
+ "/api/(gds|bongos)/atlas",
17
+ "/api/(gds|bongos)/public/repo",
18
+ "/builders/atlas.json"
19
+ ],
20
+ "ignoreConsole": [
21
+ "/api/(gds|bongos)/",
22
+ "\\b401\\b",
23
+ "\\b403\\b",
24
+ "\\b404\\b",
25
+ "\\b501\\b",
26
+ "Unauthorized",
27
+ "Forbidden",
28
+ "Not Found",
29
+ "Not Implemented",
30
+ "load failed"
31
+ ],
32
+ "states": {
33
+ "map": {
34
+ "auth": true,
35
+ "actions": [
36
+ [
37
+ "wait",
38
+ 900
39
+ ]
40
+ ],
41
+ "expect": {
42
+ "visible": [
43
+ "#scene"
44
+ ]
45
+ }
46
+ },
47
+ "out": {
48
+ "auth": false
49
+ }
50
+ },
51
+ "reducedMotion": {
52
+ "auth": true,
53
+ "actions": [
54
+ [
55
+ "wait",
56
+ 600
57
+ ]
58
+ ]
59
+ }
60
+ }
@@ -5,10 +5,10 @@
5
5
  .cb-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
6
6
 
7
7
  .cb-item {
8
- border: 1px solid var(--rule);
8
+ border: var(--line) solid var(--rule);
9
9
  border-left: 3px solid var(--rule);
10
10
  border-radius: var(--radius-sm);
11
- background: var(--surface);
11
+ background: var(--bg-card);
12
12
  padding: 10px 12px;
13
13
  }
14
14
 
@@ -19,7 +19,13 @@
19
19
  <div class="app-body">
20
20
  <header class="app-topbar" id="app-topbar"></header>
21
21
  <div class="app-content">
22
- <div class="page-head">
22
+ <!-- task 1003307: the board page head. Collab shipped with NO <h1> at all
23
+ (one-header-main-h1 measured 0 on every render), so the re-skin
24
+ carries the structural fix rather than porting the hole. The heading
25
+ is the LABEL voice, not a display line: on a working surface the
26
+ page's own name is the least interesting thing on it. -->
27
+ <div class="page-head page-head--board">
28
+ <h1 class="page-head__h">Collab</h1>
23
29
  <p class="page-head__sub" id="cb-sub">Loading…</p>
24
30
  </div>
25
31
 
@@ -0,0 +1,60 @@
1
+ {
2
+ "_": "Collab — the two-sided ask board. ASKED OF YOU comes first because it is the half where someone is waiting, and the empty state of that half is the page's most common render. Written with the re-skin (task 1003307) so this page is MEASURED at three widths in both modes rather than looked at once.",
3
+ "page": "/builders/collab",
4
+ "surface": "hall-ui",
5
+ "stub": {
6
+ "prefix": "/builders/"
7
+ },
8
+ "modeQuery": false,
9
+ "_feeds": "The kit's own stub carries no feed for this page, so against it the page renders its EMPTY and SKELETON states — which is the point: those are states the floors must hold in. Against the hall-preview harness the same states render populated. Every declared 404 below is a fixture the harness does not carry, named rather than hidden.",
10
+ "ignoreRequests": [
11
+ "/api/(gds|bongos)/me$",
12
+ "/api/(gds|bongos)/me/",
13
+ "/api/(gds|bongos)/goals",
14
+ "/api/(gds|bongos)/inbox/",
15
+ "/api/(gds|bongos)/versions",
16
+ "/api/(gds|bongos)/collab",
17
+ "/api/(gds|bongos)/connections",
18
+ "/api/(gds|bongos)/v1/help-requests"
19
+ ],
20
+ "ignoreConsole": [
21
+ "/api/(gds|bongos)/",
22
+ "\\b401\\b",
23
+ "\\b403\\b",
24
+ "\\b404\\b",
25
+ "\\b501\\b",
26
+ "Unauthorized",
27
+ "Forbidden",
28
+ "Not Found",
29
+ "Not Implemented",
30
+ "load failed"
31
+ ],
32
+ "states": {
33
+ "board": {
34
+ "auth": true,
35
+ "actions": [
36
+ [
37
+ "wait",
38
+ 700
39
+ ]
40
+ ],
41
+ "expect": {
42
+ "visible": [
43
+ "#cb-for-me"
44
+ ]
45
+ }
46
+ },
47
+ "out": {
48
+ "auth": false
49
+ }
50
+ },
51
+ "reducedMotion": {
52
+ "auth": true,
53
+ "actions": [
54
+ [
55
+ "wait",
56
+ 600
57
+ ]
58
+ ]
59
+ }
60
+ }
@@ -17,18 +17,20 @@
17
17
  flex-direction: column;
18
18
  gap: 0.15rem;
19
19
  padding: 0.75rem 0.9rem;
20
- border: 1px solid var(--rule-soft);
21
- border-radius: 0.5rem;
22
- background: var(--surface-2);
20
+ border: var(--line) solid var(--rule-soft);
21
+ border-radius: var(--radius-sm);
22
+ background: var(--glass);
23
23
  }
24
24
  .cd-stat__n { font-size: 1.6rem; font-weight: 700; line-height: 1.1; }
25
25
  .cd-stat__l { font-size: 0.8rem; opacity: 0.7; }
26
26
 
27
27
  .cd-note { font-size: 0.85rem; opacity: 0.75; line-height: 1.5; }
28
+ /* 4px, not --radius-sm: a 10px radius on a 16px-tall inline span reads as a
29
+ pill, and the tier has no smaller token. Deliberate, not missed. */
28
30
  .cd-note code {
29
31
  padding: 0.05rem 0.3rem;
30
32
  border-radius: 0.25rem;
31
- background: var(--surface-2);
33
+ background: var(--glass);
32
34
  font-size: 0.95em;
33
35
  }
34
36
 
@@ -40,8 +42,8 @@
40
42
  .cd-dialog__input,
41
43
  .cd-dialog__text {
42
44
  padding: 0.4rem 0.6rem;
43
- border: 1px solid var(--rule-soft);
44
- border-radius: 0.35rem;
45
+ border: var(--line) solid var(--rule-soft);
46
+ border-radius: var(--radius-sm);
45
47
  background: var(--bg-deep);
46
48
  color: inherit;
47
49
  font: inherit;
@@ -56,9 +58,9 @@
56
58
 
57
59
  .cd-card {
58
60
  padding: 0.85rem 1rem;
59
- border: 1px solid var(--rule-soft);
60
- border-radius: 0.5rem;
61
- background: var(--surface-2);
61
+ border: var(--line) solid var(--rule-soft);
62
+ border-radius: var(--radius-sm);
63
+ background: var(--glass);
62
64
  }
63
65
  .cd-card--slim { padding: 0.6rem 0.8rem; }
64
66
  .cd-card__head { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin-bottom: 0.4rem; }
@@ -70,23 +72,23 @@
70
72
  leading and trailing space in a string is often exactly what is wrong. */
71
73
  .cd-quote {
72
74
  quotes: '"' '"';
73
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
75
+ font-family: var(--font-mono);
74
76
  font-size: 0.9em;
75
77
  white-space: pre-wrap;
76
78
  word-break: break-word;
77
79
  }
78
- .cd-where { font-size: 0.8rem; opacity: 0.6; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
80
+ .cd-where { font-size: 0.8rem; opacity: 0.6; font-family: var(--font-mono); }
79
81
  .cd-byline { font-size: 0.8rem; opacity: 0.65; margin-left: auto; }
80
82
  .cd-reason { margin: 0.3rem 0 0; line-height: 1.55; }
81
83
  .cd-snapshot-label { font-size: 0.8rem; opacity: 0.6; }
82
84
  .cd-closed { margin: 0.5rem 0 0; font-size: 0.85rem; opacity: 0.8; line-height: 1.5; }
83
- .cd-places { margin: 0.3rem 0 0; padding-left: 1.1rem; font-size: 0.8rem; opacity: 0.65; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
85
+ .cd-places { margin: 0.3rem 0 0; padding-left: 1.1rem; font-size: 0.8rem; opacity: 0.65; font-family: var(--font-mono); }
84
86
 
85
87
  .cd-tag {
86
88
  display: inline-block;
87
89
  padding: 0.1rem 0.45rem;
88
- border: 1px solid var(--rule);
89
- border-radius: 999px;
90
+ border: var(--line) solid var(--rule);
91
+ border-radius: var(--radius-pill);
90
92
  font-size: 0.72rem;
91
93
  letter-spacing: 0.02em;
92
94
  opacity: 0.85;
@@ -103,11 +105,14 @@
103
105
  .cd-dialog {
104
106
  width: min(34rem, 92vw);
105
107
  padding: 1.25rem;
106
- border: 1px solid var(--rule);
107
- border-radius: 0.6rem;
108
+ border: var(--line) solid var(--rule);
109
+ border-radius: var(--radius);
108
110
  background: var(--bg-card);
109
111
  color: inherit;
110
112
  }
113
+ /* The one literal this sheet keeps. Pure black with alpha used as a SCRIM is
114
+ the single exception the Fifteen Rule names, and a backdrop cannot take a
115
+ ground token: it has to darken whatever is behind it in either mode. */
111
116
  .cd-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
112
117
  .cd-dialog__h { margin: 0 0 0.5rem; font-size: 1.1rem; }
113
118
  .cd-dialog__target { margin: 0 0 0.9rem; line-height: 1.5; }
@@ -19,7 +19,15 @@
19
19
  <div class="app-body">
20
20
  <header class="app-topbar" id="app-topbar"></header>
21
21
  <div class="app-content">
22
- <div class="page-head"><p class="page-head__sub" id="cd-sub">Loading the copy desk…</p></div>
22
+ <!-- task 1003307: the board page head. Copy desk shipped with NO <h1> at all
23
+ (one-header-main-h1 measured 0 on every render), so the re-skin
24
+ carries the structural fix rather than porting the hole. The heading
25
+ is the LABEL voice, not a display line: on a working surface the
26
+ page's own name is the least interesting thing on it. -->
27
+ <div class="page-head page-head--board">
28
+ <h1 class="page-head__h">Copy desk</h1>
29
+ <p class="page-head__sub" id="cd-sub">Loading the copy desk…</p>
30
+ </div>
23
31
 
24
32
  <main id="hall-main">
25
33
  <!-- The counts. Deliberately four numbers and not a dashboard: open work,
@@ -0,0 +1,59 @@
1
+ {
2
+ "_": "Copy desk — the one-voice review queue. Its confirm dialog is a real <dialog>, so its ::backdrop is the sheet's single sanctioned literal (black with alpha as a scrim). Written with the re-skin (task 1003307) so this page is MEASURED at three widths in both modes rather than looked at once.",
3
+ "page": "/builders/copy-desk",
4
+ "surface": "hall-ui",
5
+ "stub": {
6
+ "prefix": "/builders/"
7
+ },
8
+ "modeQuery": false,
9
+ "_feeds": "The kit's own stub carries no feed for this page, so against it the page renders its EMPTY and SKELETON states — which is the point: those are states the floors must hold in. Against the hall-preview harness the same states render populated. Every declared 404 below is a fixture the harness does not carry, named rather than hidden.",
10
+ "ignoreRequests": [
11
+ "/api/(gds|bongos)/me$",
12
+ "/api/(gds|bongos)/me/",
13
+ "/api/(gds|bongos)/goals",
14
+ "/api/(gds|bongos)/inbox/",
15
+ "/api/(gds|bongos)/versions",
16
+ "/api/(gds|bongos)/copy",
17
+ "/api/(gds|bongos)/security/"
18
+ ],
19
+ "ignoreConsole": [
20
+ "/api/(gds|bongos)/",
21
+ "\\b401\\b",
22
+ "\\b403\\b",
23
+ "\\b404\\b",
24
+ "\\b501\\b",
25
+ "Unauthorized",
26
+ "Forbidden",
27
+ "Not Found",
28
+ "Not Implemented",
29
+ "load failed"
30
+ ],
31
+ "states": {
32
+ "queue": {
33
+ "auth": true,
34
+ "actions": [
35
+ [
36
+ "wait",
37
+ 700
38
+ ]
39
+ ],
40
+ "expect": {
41
+ "visible": [
42
+ "#cd-summary-scroll"
43
+ ]
44
+ }
45
+ },
46
+ "out": {
47
+ "auth": false
48
+ }
49
+ },
50
+ "reducedMotion": {
51
+ "auth": true,
52
+ "actions": [
53
+ [
54
+ "wait",
55
+ 600
56
+ ]
57
+ ]
58
+ }
59
+ }
@@ -9,9 +9,15 @@
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
+ <!-- task 1003307: the reading-room archetype's own sheet. drachmae reuses the
13
+ primer's layout and loaded primer.css for it, but never room.css — so it
14
+ had the room's DOM and none of the room's world: no reading measure, no
15
+ prose-link 24px floor, no table wrapper. Loading it is the fix; the order
16
+ matches primer.html (room first, the page's own sheet on top). -->
17
+ <link rel="stylesheet" href="/builders/room.css">
12
18
  <link rel="stylesheet" href="/builders/primer.css?v=2026-07-02-shell1">
13
19
  </head>
14
- <body class="primer-body" data-page="drachmae" data-page-title="Drachmae &amp; karma">
20
+ <body class="room primer-body" data-page="drachmae" data-page-title="Drachmae &amp; karma">
15
21
 
16
22
  <!-- Reading-progress bar — fills as the reader scrolls through the article. -->
17
23
  <div class="primer-progress" aria-hidden="true"><div class="primer-progress__bar" id="primer-progress-bar"></div></div>
@@ -23,7 +29,13 @@
23
29
  <header class="app-topbar" id="app-topbar"></header>
24
30
  <div class="app-content">
25
31
 
26
- <div class="page-head">
32
+ <!-- task 1003307: the reading-room head. drachmae shares the primer's
33
+ .primer-layout and is read as a document, so it takes .page-head--room
34
+ (task 1003306's archetype) rather than the board's label voice — and
35
+ it gets the <h1> it never had. -->
36
+ <div class="page-head page-head--room">
37
+ <p class="page-head__eyebrow">Docs</p>
38
+ <h1 class="page-head__h">Drachmae &amp; karma</h1>
27
39
  <p class="page-head__sub">How you get paid, and how you earn trust — the reward model in plain language. About a five-minute read.</p>
28
40
  </div>
29
41
 
@@ -45,9 +57,30 @@
45
57
  </aside>
46
58
 
47
59
  <!-- Article column — markdown rendered here. -->
48
- <article class="primer-article" id="primer-article" aria-busy="true">
49
- <div class="primer-loading">Loading the drachmae guide…</div>
50
- </article>
60
+ <!-- The room's loading shape: skeleton lines in the article's own
61
+ measure, not a sentence. (.primer-loading, which used to sit in the
62
+ article, is defined in no stylesheet and rendered unstyled.) -->
63
+ <div class="primer-skeleton scroll" id="primer-skeleton" aria-hidden="true">
64
+ <span class="primer-sk primer-skeleton__h"></span>
65
+ <div class="primer-skeleton__p">
66
+ <span class="primer-sk"></span>
67
+ <span class="primer-sk"></span>
68
+ <span class="primer-sk"></span>
69
+ </div>
70
+ <div class="primer-skeleton__rule"></div>
71
+ <div class="primer-skeleton__p">
72
+ <span class="primer-sk"></span>
73
+ <span class="primer-sk"></span>
74
+ </div>
75
+ </div>
76
+
77
+ <article class="primer-article scroll" id="primer-article" aria-busy="true" hidden></article>
78
+
79
+ <div class="primer-note primer-note--error scroll" id="primer-error" hidden>
80
+ <p class="primer-note__label">The guide did not load</p>
81
+ <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>
82
+ <p class="primer-note__acts"><a class="btn btn--ghost" href="/builders">Back to home</a></p>
83
+ </div>
51
84
 
52
85
  </div>
53
86
  </main>
@@ -146,9 +146,21 @@
146
146
  });
147
147
  }
148
148
 
149
+ // The three panels the article can resolve into (the primer's show(), which
150
+ // this page's DOM has mirrored since task 1472 and now finally matches).
151
+ function show(which) {
152
+ for (const [id, on] of [['#primer-skeleton', which === 'loading'],
153
+ ['#primer-article', which === 'article'],
154
+ ['#primer-error', which === 'error']]) {
155
+ const el = $(id);
156
+ if (el) el.hidden = !on;
157
+ }
158
+ }
159
+
149
160
  async function boot() {
150
161
  const article = $('#primer-article');
151
162
  if (!article || !window.OTBMdReader) return;
163
+ show('loading');
152
164
  let md;
153
165
  try {
154
166
  const [mdRes] = await Promise.all([
@@ -159,8 +171,8 @@
159
171
  md = await mdRes.text();
160
172
  } catch (err) {
161
173
  console.error('[drachmae] failed to load doc', err);
162
- article.innerHTML = `<p class="primer-loading">Could not load the drachmae guide. <a href="/builders">Go back</a> and try again.</p>`;
163
174
  article.removeAttribute('aria-busy');
175
+ show('error');
164
176
  return;
165
177
  }
166
178
  const resolveLinkHref = window.OTBMdReader.makeResolveLinkHref({
@@ -169,9 +181,15 @@
169
181
  getTreeBase: () => repoTreeBase,
170
182
  diagramsHref: '/builders/diagrams',
171
183
  });
172
- const { html, headings } = window.OTBMdReader.parseMarkdown(md, resolveLinkHref);
184
+ const parsed = window.OTBMdReader.parseMarkdown(md, resolveLinkHref);
185
+ // The doc's leading "# …" is the same page name .page-head--room already
186
+ // renders. Two <h1>s fails one-header-main-h1, and the page head is the one
187
+ // that exists before the fetch and survives its failure (task 1003307).
188
+ const html = parsed.html.replace(/^\s*<h1\b[^>]*>[\s\S]*?<\/h1>\s*/, '');
189
+ const headings = parsed.headings.filter((h) => h.level > 1);
173
190
  article.innerHTML = html;
174
191
  article.removeAttribute('aria-busy');
192
+ show('article');
175
193
  // Awaited before the TOC is built so the rate card gets a TOC entry and a
176
194
  // scrollspy target; the article itself is already on screen by now.
177
195
  const bountyHeading = await appendBountySection(article);
@@ -0,0 +1,64 @@
1
+ {
2
+ "_": "Drachmae & karma — a READING ROOM, not a board: it shares the primer .primer-layout and takes .page-head--room. Public (no page gate), so the signed-out render is the one most readers get. Written with the re-skin (task 1003307) so this page is MEASURED at three widths in both modes rather than looked at once.",
3
+ "page": "/builders/drachmae",
4
+ "surface": "hall-ui",
5
+ "stub": {
6
+ "prefix": "/builders/"
7
+ },
8
+ "modeQuery": false,
9
+ "_feeds": "The kit's own stub carries no feed for this page, so against it the page renders its EMPTY and SKELETON states — which is the point: those are states the floors must hold in. Against the hall-preview harness the same states render populated. Every declared 404 below is a fixture the harness does not carry, named rather than hidden.",
10
+ "ignoreRequests": [
11
+ "/api/(gds|bongos)/me$",
12
+ "/api/(gds|bongos)/me/",
13
+ "/api/(gds|bongos)/goals",
14
+ "/api/(gds|bongos)/inbox/",
15
+ "/api/(gds|bongos)/versions"
16
+ ],
17
+ "ignoreConsole": [
18
+ "/api/(gds|bongos)/",
19
+ "\\b401\\b",
20
+ "\\b403\\b",
21
+ "\\b404\\b",
22
+ "\\b501\\b",
23
+ "Unauthorized",
24
+ "Forbidden",
25
+ "Not Found",
26
+ "Not Implemented",
27
+ "load failed"
28
+ ],
29
+ "states": {
30
+ "read": {
31
+ "auth": true,
32
+ "actions": [
33
+ [
34
+ "wait",
35
+ 600
36
+ ]
37
+ ],
38
+ "expect": {
39
+ "visible": [
40
+ "#primer-article",
41
+ "#primer-toc"
42
+ ]
43
+ }
44
+ },
45
+ "out": {
46
+ "auth": false,
47
+ "actions": [
48
+ [
49
+ "wait",
50
+ 600
51
+ ]
52
+ ]
53
+ }
54
+ },
55
+ "reducedMotion": {
56
+ "auth": true,
57
+ "actions": [
58
+ [
59
+ "wait",
60
+ 600
61
+ ]
62
+ ]
63
+ }
64
+ }