@bongos/core 1.19.484 → 1.19.486

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 +102 -52
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +6 -0
  4. package/clients/bongos-client/index.cjs +6 -0
  5. package/clients/bongos-client/index.d.ts +7 -0
  6. package/clients/bongos-client/index.mjs +6 -0
  7. package/docs/adr/0232-rot-is-derived-not-swept-and-water-is-the-only-new-verb.md +155 -0
  8. package/docs/adr/README.md +1 -0
  9. package/docs/api/openapi.json +147 -3
  10. package/docs/api-reference.md +7 -4
  11. package/docs/copy-inventory.md +169 -178
  12. package/docs/copy-registry.json +295 -405
  13. package/docs/file-map.md +1 -1
  14. package/docs/module-api-changelog.md +4 -0
  15. package/migrations/core_231_project_settings_and_attention_water.sql +163 -0
  16. package/modules/dev-box/app/src/vendor/bongos-client.cjs +6 -0
  17. package/modules/hall-ui/public/goal-inbox.js +119 -1
  18. package/modules/hall-ui/public/not-ready.html +14 -10
  19. package/modules/hall-ui/public/not-ready.states.json +14 -0
  20. package/modules/hall-ui/public/pair.css +17 -67
  21. package/modules/hall-ui/public/pair.html +8 -1
  22. package/modules/hall-ui/public/pair.states.json +14 -0
  23. package/modules/hall-ui/public/panel.css +333 -0
  24. package/modules/hall-ui/public/profile.css +85 -0
  25. package/modules/hall-ui/public/profile.html +12 -5
  26. package/modules/hall-ui/public/profile.states.json +15 -0
  27. package/modules/hall-ui/public/settings.css +119 -336
  28. package/modules/hall-ui/public/settings.html +28 -19
  29. package/modules/hall-ui/public/settings.js +44 -35
  30. package/modules/hall-ui/public/settings.states.json +16 -0
  31. package/modules/hall-ui/public/style.css +5 -2
  32. package/modules/lifecycle/module.json +2 -1
  33. package/modules/lifecycle/rot.js +210 -0
  34. package/modules/lifecycle/routes/rot.js +160 -0
  35. package/package-lock.json +2 -2
  36. package/package.json +1 -1
  37. package/scripts/gds/fitness-checks-vocabulary.js +0 -1
  38. package/scripts/gds/fitness.js +9 -0
  39. package/src/bongos/project-settings.js +193 -0
  40. package/src/module-api.js +29 -1
  41. package/tests/hall_settings_world.mjs +274 -0
  42. package/tests/join_application_note.mjs +7 -15
  43. package/tests/module-scope-map.mjs +1 -1
  44. package/tests/module_api.mjs +1 -0
  45. package/tests/rot_inbox.mjs +532 -0
  46. package/modules/hall-ui/public/my-projects.css +0 -62
  47. package/modules/hall-ui/public/my-projects.html +0 -73
  48. package/modules/hall-ui/public/my-projects.js +0 -153
@@ -1,14 +1,18 @@
1
- /* settings.css — page-local styles for Settings (task 2172; extracted from
2
- settings.html's old inline <style> per the hall placement rules). Components
3
- layered on the shared design system (style.css) — the rail (.section-rail /
4
- .rail-link) and buttons derive from the shared tokens so instance theme
5
- packs reskin this page too. */
1
+ /* settings.css — what Settings has and the rest of the panel family does not
2
+ (task 1003308, goal 1000081; the archetype is panel.css). The grouped layout
3
+ behind the section rail, the group head, the token ladder, the voices grid,
4
+ the volume line and the image-key banner. Every colour is a `var()` of the
5
+ world's tier; the one literal pair is the Discord mark, named below.
6
6
 
7
- /* ---- grouped layout: left sub-nav rail + one visible group (task 1723) ---- */
7
+ The rail itself (.section-rail / .rail-link) is the shell's, built by
8
+ OTBKit.makeSectionRail in switch mode; this sheet only widens its column to
9
+ the mock's and keeps one group visible at a time. */
10
+
11
+ /* ---- grouped layout: left rail + one visible group ------------------------ */
8
12
  .settings-layout {
9
13
  display: grid;
10
- grid-template-columns: 180px minmax(0, 1fr);
11
- gap: 20px;
14
+ grid-template-columns: 206px minmax(0, 1fr);
15
+ gap: 30px;
12
16
  align-items: start;
13
17
  }
14
18
  .settings-layout[hidden] { display: none !important; }
@@ -24,357 +28,136 @@
24
28
  .settings-groups[data-active="sound"] > [data-group="sound"],
25
29
  .settings-groups[data-active="extensions"] > [data-group="extensions"] { display: block; }
26
30
  .settings-groups > [data-group][hidden] { display: none !important; }
31
+ .settings-groups .scroll { margin: 0 0 var(--sp-sm); }
32
+ .settings-groups .scroll__lede { font-size: 14.5px; }
33
+ /* the rail's items at the mock's height: the shell's 28px rows are Standing's
34
+ density, and a settings group is a destination, not a scroll-spy stop */
35
+ #settings-rail .rail-link { min-height: 38px; padding: 0 14px; font-size: 14.5px; text-transform: none; border-radius: var(--radius-pill); }
36
+ #settings-rail .rail-link--active::before { left: 0; top: 7px; bottom: 7px; }
27
37
 
28
- /* task 2172 density pass — standard panel anatomy (title → one-line purpose →
29
- control → save-semantics note) in a tighter card: less padding + stacking
30
- margin than the default .scroll, ledes clamped to one visual line's worth. */
31
- .settings-groups .scroll { padding: 16px 18px; margin: 0 0 12px; }
32
- .settings-groups .scroll__lede { font-size: 13px; margin-bottom: 10px; }
38
+ /* the group head: the group's name in the display voice over a hairline, with
39
+ its own address in the mono face beside it (a machine's word keeps its case) */
40
+ .grp__head {
41
+ display: flex;
42
+ align-items: baseline;
43
+ justify-content: space-between;
44
+ gap: var(--sp-sm);
45
+ margin: 0 0 var(--sp-sm);
46
+ padding-bottom: var(--sp-xs);
47
+ border-bottom: var(--line) solid var(--glass-edge);
48
+ }
49
+ .grp__h { margin: 0; font-family: var(--font-display); font-weight: 300; font-size: clamp(22px, 2.1vw, 29px); line-height: 1.1; letter-spacing: -.03em; color: var(--ink); }
50
+ .grp__eyebrow { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0; text-transform: none; color: var(--ink-faint); }
33
51
 
34
- @media (max-width: 768px) {
52
+ @media (max-width: 860px) {
35
53
  /* Collapse to one column; the shared .section-rail ≤768px rules turn the
36
- rail into a sticky horizontal chip strip just under the top bar. */
37
- .settings-layout { grid-template-columns: minmax(0, 1fr); }
54
+ rail into a horizontal chip strip just under the top bar. */
55
+ .settings-layout { grid-template-columns: minmax(0, 1fr); gap: var(--sp-md); }
38
56
  }
39
-
40
- .settings-status {
41
- font-size: 13px;
42
- color: var(--ink-soft);
43
- min-height: 1.2em;
44
- margin-top: 8px;
45
- }
46
- .section-note {
47
- color: var(--ink-faint);
48
- font-size: 12.5px;
49
- margin-top: 10px;
50
- margin-bottom: 0;
57
+ @media (max-width: 520px) {
58
+ .grp__head { flex-direction: column; align-items: flex-start; gap: 4px; }
51
59
  }
52
60
 
53
- /* ---- Voices (per-skill model picker) ---- */
54
- .voices-scroll { /* keep many rows compact within a bounded, scrollable box */ }
55
- .voices-wrap {
56
- max-height: 460px;
57
- overflow-y: auto;
58
- margin-top: 6px;
59
- border: 1px solid var(--border);
61
+ /* ---- the token ladder (CLI access) ------------------------------------------
62
+ A 64-character token cannot be a line of prose, so it is quoted: one tonal
63
+ step down from the panel, the machine's words receding to the soft ink so the
64
+ secret itself is the only ink on the line. */
65
+ .cli-result { flex-basis: 100%; margin-top: var(--sp-xs); }
66
+ .cli-result__say { margin: 0 0 var(--sp-xs); font-size: 14.5px; color: var(--ink); }
67
+ .quote {
68
+ background: var(--glass);
69
+ border: var(--line) solid var(--glass-edge);
60
70
  border-radius: var(--radius-sm);
71
+ padding: var(--sp-xs) var(--sp-sm) var(--sp-hair);
61
72
  }
62
- table.voices {
63
- width: 100%;
64
- border-collapse: collapse;
73
+ .quote__eyebrow { margin: 0 0 var(--sp-hair); font-family: var(--label-face); font-size: var(--label-size); letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
74
+ .quote__pre {
75
+ margin: 0;
76
+ font-family: var(--font-mono);
65
77
  font-size: 13px;
78
+ line-height: 1.6;
66
79
  color: var(--ink);
80
+ white-space: pre-wrap;
81
+ overflow-wrap: anywhere;
82
+ word-break: break-all;
67
83
  }
68
- table.voices th, table.voices td {
69
- padding: 7px 12px;
70
- text-align: left;
71
- border-bottom: 1px solid var(--rule-soft);
72
- vertical-align: middle;
73
- }
74
- table.voices th {
75
- /* sticks inside .voices-wrap's own scroller, not the window — top:0 is
76
- relative to the wrap, so no --topbar-h offset needed here */
77
- position: sticky;
78
- top: 0;
79
- z-index: 1;
80
- background: var(--surface);
81
- font-size: 11px;
82
- font-weight: 600;
83
- letter-spacing: 0.06em;
84
- text-transform: uppercase;
85
- color: var(--ink-faint);
86
- border-bottom: 1px solid var(--border-strong);
87
- }
88
- table.voices tr:last-child td { border-bottom: none; }
89
- table.voices tbody tr:hover td { background: var(--surface-2); }
90
- .voices__skill code {
91
- font-size: 12.5px;
92
- color: var(--info);
93
- }
94
- .voices__default {
95
- font-size: 12.5px;
96
- color: var(--ink-soft);
97
- }
98
- select.voices__select { min-width: 140px; }
99
- .voices-empty, .craft-empty {
100
- color: var(--ink-faint);
101
- font-style: italic;
102
- font-size: 13px;
103
- padding: 10px 0;
104
- }
105
-
106
- /* ---- Sounds (per-sound on/off toggles) ---- */
107
- .sound-rows { margin-top: 8px; }
108
- .sound-row {
109
- display: flex;
110
- align-items: center;
111
- justify-content: space-between;
112
- gap: 16px;
113
- padding: 9px 0;
114
- border-bottom: 1px solid var(--rule-soft);
115
- }
116
- .sound-row:last-child { border-bottom: none; }
117
- .sound-row__text { min-width: 0; }
118
- .sound-row__label {
119
- font-size: 13.5px;
120
- color: var(--ink);
121
- font-weight: 600;
122
- }
123
- .sound-row__desc {
124
- font-size: 12.5px;
125
- color: var(--ink-soft);
126
- margin-top: 2px;
127
- }
128
- button.sound-toggle {
129
- font-family: var(--font-body);
130
- font-size: 12.5px;
131
- font-weight: 600;
132
- padding: 5px 16px;
133
- min-width: 72px;
134
- border-radius: 999px;
135
- border: 1px solid var(--border-strong);
136
- background: var(--surface);
137
- color: var(--ink-soft);
138
- cursor: pointer;
139
- flex-shrink: 0;
140
- }
141
- button.sound-toggle[data-on="1"] {
142
- background: var(--accent);
143
- border-color: var(--accent);
144
- color: #fff;
145
- }
146
- button.sound-toggle:disabled { opacity: 0.5; cursor: default; }
147
- .sound-volume {
148
- display: flex;
149
- align-items: center;
150
- gap: 14px;
151
- padding: 4px 0 12px;
152
- border-bottom: 1px solid var(--border);
153
- margin-bottom: 4px;
154
- }
155
- .sound-volume__label {
156
- font-size: 11px;
157
- font-weight: 600;
158
- text-transform: uppercase;
159
- letter-spacing: 0.06em;
160
- color: var(--ink-faint);
161
- flex-shrink: 0;
162
- }
163
- .sound-volume input[type="range"] {
164
- flex: 1;
165
- accent-color: var(--accent);
166
- cursor: pointer;
167
- }
168
- .sound-volume__pct {
169
- font-size: 13px;
170
- color: var(--ink);
171
- min-width: 3.2em;
172
- text-align: right;
173
- font-variant-numeric: tabular-nums;
174
- }
175
-
176
- /* ---- Event sounds (per-event variant dropdowns, task 582) ---- */
177
- .event-sound-rows { margin-top: 8px; }
178
- .event-sound-row {
179
- display: flex;
180
- align-items: center;
181
- justify-content: space-between;
182
- gap: 16px;
183
- padding: 9px 0;
184
- border-bottom: 1px solid var(--rule-soft);
185
- }
186
- .event-sound-row:last-child { border-bottom: none; }
187
- .event-sound-row__text { flex: 1; min-width: 0; }
188
- .event-sound-row__label {
189
- font-size: 13.5px;
190
- color: var(--ink);
191
- font-weight: 600;
192
- }
193
- .event-sound-row__desc {
194
- font-size: 12.5px;
195
- color: var(--ink-soft);
196
- margin-top: 2px;
197
- }
198
- .event-sound-row__controls {
199
- display: flex;
200
- align-items: center;
201
- gap: 8px;
202
- flex-shrink: 0;
203
- }
204
- .event-sound-select { cursor: pointer; }
205
- .event-sound-preview {
206
- font-family: var(--font-body);
207
- font-size: 12px;
208
- font-weight: 600;
209
- padding: 5px 12px;
210
- border-radius: 999px;
211
- border: 1px solid var(--border-strong);
212
- background: transparent;
213
- color: var(--ink-soft);
214
- cursor: pointer;
215
- }
216
- .event-sound-preview:active { opacity: 0.7; }
217
-
218
- /* ---- Disciplines (preference chips) ---- */
219
- .craft-chips {
84
+ .quote__foot {
220
85
  display: flex;
221
86
  flex-wrap: wrap;
222
- gap: 10px;
223
- margin-top: 8px;
224
- }
225
- .craft-chip {
226
- display: inline-flex;
227
- align-items: center;
228
- gap: 8px;
229
- font-size: 13.5px;
230
- color: var(--ink);
231
- background: var(--surface);
232
- border: 1px solid var(--border-strong);
233
- border-radius: 999px;
234
- padding: 6px 14px;
235
- cursor: pointer;
236
- user-select: none;
237
- text-transform: capitalize;
238
- }
239
- .craft-chip:hover { background: var(--surface-2); }
240
- .craft-chip input { cursor: pointer; }
241
- .craft-chip[data-on="1"] {
242
- background: var(--accent);
243
- border-color: var(--accent);
244
- color: #fff;
245
- }
246
- .craft-actions {
247
- display: flex;
248
87
  align-items: center;
249
- gap: 14px;
250
- margin-top: 14px;
251
- flex-wrap: wrap;
252
- }
253
-
254
- /* ---- Buttons (Save / card actions) ---- */
255
- button.craft-save, .settings-btn {
256
- font-family: var(--font-body);
257
- font-size: 13px;
258
- font-weight: 600;
259
- padding: 7px 16px;
260
- border: 1px solid var(--accent);
261
- background: var(--surface);
262
- color: var(--accent-text);
263
- border-radius: var(--radius-sm);
264
- cursor: pointer;
265
- display: inline-block;
266
- text-decoration: none;
267
- }
268
- button.craft-save:hover:not(:disabled), .settings-btn:hover:not(:disabled) {
269
- background: var(--accent);
270
- color: #fff;
271
- text-decoration: none;
272
- }
273
- button.craft-save:disabled, .settings-btn:disabled { opacity: 0.5; cursor: default; }
274
- /* Discord brand button — keeps its blurple so it's recognisable. */
275
- .settings-btn--discord {
276
- background: #5865F2;
277
- border-color: #4853c4;
278
- color: #fff;
88
+ gap: var(--sp-xs);
89
+ margin-top: var(--sp-xs);
90
+ padding-top: var(--sp-hair);
91
+ border-top: var(--line) solid var(--glass-edge);
279
92
  }
280
- .settings-btn--discord:hover { background: #4853c4; color: #fff; }
281
- .settings-btn--quiet {
282
- border-color: var(--border-strong);
283
- color: var(--ink-soft);
284
- }
285
- .settings-btn--quiet:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
286
93
 
287
- /* ---- Display name (single editable field, task 1669) ---- */
288
- .display-name-row {
289
- display: flex;
290
- flex-wrap: wrap;
291
- align-items: center;
292
- gap: 12px;
293
- margin-top: 8px;
294
- }
295
- input.display-name-input {
296
- flex: 1 1 280px;
297
- min-width: 0;
298
- }
94
+ /* ---- active sessions --------------------------------------------------------
95
+ The name is a run with its pill and the agent beside it, then the when-line
96
+ underneath; a row of the family otherwise. */
97
+ .sessions-row__main > strong { display: inline; }
98
+ .sessions-row__agent { display: inline; margin-left: 8px; }
99
+ .sessions-row__when { display: block; }
299
100
 
300
- /* ---- Connections + CLI access cards ---- */
301
- .settings-card {
302
- margin-top: 8px;
303
- display: flex;
304
- flex-wrap: wrap;
305
- align-items: center;
306
- gap: 12px;
307
- }
308
- .settings-card__hint { color: var(--ink-soft); font-size: 13px; }
309
- .settings-card__ok { font-weight: 600; color: var(--ok); }
310
- .cli-result { flex-basis: 100%; margin-top: 4px; }
311
- .cli-result pre {
312
- background: var(--bg-deep);
313
- color: var(--ink);
314
- padding: 10px 12px;
315
- border: 1px solid var(--border);
316
- border-radius: var(--radius-sm);
317
- overflow-x: auto;
318
- font-size: 12.5px;
319
- margin: 6px 0;
101
+ /* ---- Voices (per-skill model picker) ------------------------------------- */
102
+ .voices-wrap { margin-top: var(--sp-sm); overflow-x: auto; }
103
+ table.voices { width: 100%; border-collapse: collapse; text-align: left; font-size: 14px; color: var(--ink); }
104
+ table.voices th, table.voices td {
105
+ padding: var(--sp-xs) var(--sp-xs) var(--sp-xs) 0;
106
+ vertical-align: middle;
107
+ border-top: var(--line) solid var(--rule-soft);
108
+ }
109
+ table.voices thead th {
110
+ padding-top: 0;
111
+ border-top: 0;
112
+ border-bottom: var(--line) solid var(--rule);
113
+ font-family: var(--label-face);
114
+ font-size: var(--label-size);
115
+ font-weight: 400;
116
+ letter-spacing: var(--label-space);
117
+ text-transform: var(--label-case);
118
+ color: var(--ink-faint);
119
+ white-space: nowrap;
320
120
  }
121
+ .voices__skill { white-space: nowrap; }
122
+ .voices__skill code { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-soft); }
123
+ .voices__default { margin-left: 0; font-family: var(--font-body); font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--ink-soft); }
124
+ td.voices__choice { width: 1%; white-space: nowrap; }
125
+ select.voices__select { min-width: 140px; }
126
+ .voices-empty, .craft-empty { padding: var(--sp-xs) 0; font-size: 13.5px; color: var(--ink-faint); }
321
127
 
322
- /* ---- Active sessions (task 1003341) — one row per live session, the current
323
- one badged so nobody ends the page they are reading. ---- */
324
- .sessions-row {
325
- display: flex;
326
- flex-wrap: wrap;
327
- align-items: center;
328
- justify-content: space-between;
329
- gap: 10px;
330
- padding: 10px 0;
331
- border-bottom: 1px solid var(--border);
332
- }
333
- .sessions-row:last-child { border-bottom: 0; }
334
- .sessions-row__main { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; min-width: 0; }
335
- .sessions-row__agent,
336
- .sessions-row__when { color: var(--ink-soft); font-size: 13px; }
337
- .sessions-row__agent { overflow-wrap: anywhere; }
338
- .sessions-row__when { flex-basis: 100%; }
339
- .sessions-row__badge {
340
- font-size: 12px;
341
- padding: 1px 7px;
342
- border: 1px solid var(--border);
343
- border-radius: var(--radius-sm);
344
- color: var(--ink-soft);
345
- }
128
+ /* ---- Sounds: the volume line ------------------------------------------- */
129
+ .sound-volume { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); margin-bottom: var(--sp-xs); }
130
+ .sound-volume .field-label { margin: 0; }
131
+ .sound-volume__pct { min-width: 3.2em; font-size: 13px; color: var(--ink-faint); text-align: right; font-variant-numeric: tabular-nums; }
346
132
 
347
- /* ---- Image key (task 1013) — the "we cover it" / "action needed" banner
348
- uses the shared semantic status tokens. ---- */
133
+ /* ---- Image key: the covered / action-needed banner ------------------------ */
349
134
  .artkey-banner {
350
- border-radius: var(--radius-sm);
351
- padding: 10px 14px;
352
- font-size: 13px;
135
+ margin: 0 0 var(--sp-sm);
136
+ padding: var(--sp-xs) var(--sp-sm);
137
+ font-size: 14px;
353
138
  line-height: 1.45;
354
- border: 1px solid var(--border);
355
- margin-bottom: 10px;
356
- }
357
- .artkey-banner--covered {
358
- background: var(--ok-weak);
359
- border-color: color-mix(in srgb, var(--ok) 45%, var(--border));
360
- color: var(--ok);
361
- }
362
- .artkey-banner--action {
139
+ color: var(--ink);
140
+ border-left: 2px solid var(--warn);
363
141
  background: var(--warn-weak);
364
- border-color: color-mix(in srgb, var(--warn) 45%, var(--border));
365
- color: var(--warn);
366
- }
367
- .artkey-entry-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; flex-basis: 100%; }
368
- .artkey-input {
369
- flex: 1 1 280px;
370
- min-width: 0;
371
- padding: 7px 10px;
372
- border: 1px solid var(--border-strong);
373
142
  border-radius: var(--radius-sm);
374
- background: var(--surface);
375
- color: var(--ink);
376
- font-family: ui-monospace, "SF Mono", Menlo, monospace;
377
- font-size: 13px;
378
143
  }
379
- .artkey-actions { display: flex; gap: 10px; flex-wrap: wrap; }
144
+ .artkey-banner--covered { border-left-color: var(--ok); background: var(--ok-weak); }
145
+ .artkey-banner strong { font-weight: 500; }
380
146
  #artkey-entry { flex-basis: 100%; }
147
+ /* the entry renders inside the card's flex row, so its label takes the row */
148
+ #artkey-card > .field-label, #artkey-entry > .field-label { flex: 1 1 100%; margin-top: 0; }
149
+ #artkey-entry[hidden] { display: none; }
150
+ .artkey-entry-row { flex-basis: 100%; }
151
+
152
+ /* ---- Discord -----------------------------------------------------------------
153
+ THIRD-PARTY MARK, KEPT ON PURPOSE. Discord's blurple is Discord's, not the
154
+ world's: the button is recognisable as theirs only in their colour, and the
155
+ link opens their consent screen. These two literals are the one sanctioned
156
+ exception in this sheet — a future literal sweep must leave them alone. */
157
+ .settings-btn--discord { background: #5865F2; border-color: #4853c4; color: #ffffff; }
158
+ .settings-btn--discord:hover:not(:disabled) { background: #4853c4; border-color: #4853c4; color: #ffffff; }
159
+
160
+ /* ---- dev box ------------------------------------------------------------- */
161
+ /* the box panel is the shell's (.setup__box, box-panel.js); inside a settings
162
+ panel it sits on the glass rather than a second card */
163
+ .settings-groups .setup__box { margin: var(--sp-sm) 0 0; background: var(--glass); border-color: var(--glass-edge); border-radius: var(--radius-sm); }
@@ -9,9 +9,11 @@
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
- <!-- Page-local styles (task 2172) — extracted from the old inline <style>
13
- block per the hall placement rules; the rail comes from style.css's
14
- shared .section-rail/.rail-link rules. -->
12
+ <!-- The PANEL archetype (task 1003308): the row, the switch, the field, the
13
+ chip control and the family's voices, shared with profile, pair and
14
+ not-ready. settings.css then holds only what this page
15
+ has — the rail layout, the group head, the token ladder, the voices grid. -->
16
+ <link rel="stylesheet" href="/builders/panel.css">
15
17
  <link rel="stylesheet" href="/builders/settings.css">
16
18
  </head>
17
19
  <body data-page="settings" data-page-title="Settings">
@@ -22,15 +24,22 @@
22
24
  <div class="app-body">
23
25
  <header class="app-topbar" id="app-topbar"></header>
24
26
  <div class="app-content">
25
- <div class="page-head"><p class="page-head__sub" id="settings-sub">Loading your preferences…</p></div>
27
+ <!-- The page's ONE h1 (one-header-main-h1): the page's own name in the
28
+ room voice, because here the document is the page. The sub-line is
29
+ settings.js's — "Your preferences, <name>." and the two failure states. -->
30
+ <div class="page-head page-head--room page-head--panel">
31
+ <h1 id="settings-h1" class="page-head__h">settings</h1>
32
+ <p class="page-head__sub" id="settings-sub">Loading your preferences…</p>
33
+ </div>
26
34
 
27
35
  <main id="hall-main">
28
36
  <!-- Not-signed-in notice — shown by settings.js before it redirects, and
29
37
  as a fallback if reading the viewer fails. Deliberately OUTSIDE the
30
38
  grouped layout: full-width, ungrouped. -->
31
- <section class="scroll" id="gate-scroll" aria-labelledby="gate-h" hidden>
32
- <h2 id="gate-h" class="scroll__h">Not signed in</h2>
33
- <p class="scroll__lede" id="gate-body">You're not signed in yet. Sign in to manage your preferences.</p>
39
+ <section class="scroll gate" id="gate-scroll" aria-labelledby="gate-h" hidden>
40
+ <h2 id="gate-h" class="gate__h">Not signed in</h2>
41
+ <p class="gate__lede" id="gate-body">You're not signed in yet. Sign in to manage your connections, your keys, your dev box and the way the hall behaves.</p>
42
+ <div class="row-end"><a class="pbtn pbtn--save" href="/api/bongos/auth/web/start">Sign in</a></div>
34
43
  </section>
35
44
 
36
45
  <!-- Grouped layout (task 1723 → kit, task 2172): the sections sit in six
@@ -68,10 +77,11 @@
68
77
  and the work feed. Your sign-in and the credit for shipped work stay
69
78
  tied to your account, not this label.
70
79
  </p>
80
+ <label class="field-label" for="display-name-input">Display name</label>
71
81
  <div class="display-name-row">
72
82
  <input type="text" class="display-name-input" id="display-name-input"
73
83
  maxlength="60" autocomplete="off" spellcheck="false"
74
- aria-label="Display name" placeholder="Your display name">
84
+ placeholder="Your display name">
75
85
  <button type="button" class="craft-save" id="display-name-save">Save</button>
76
86
  </div>
77
87
  <p class="settings-status" id="display-name-status" role="status" aria-live="polite"></p>
@@ -158,7 +168,7 @@
158
168
  </p>
159
169
  <div id="sessions-list" class="sessions-list" aria-live="polite"></div>
160
170
  <div class="settings-card">
161
- <button type="button" class="settings-btn" id="sessions-revoke-all">Sign out everywhere</button>
171
+ <button type="button" class="settings-btn settings-btn--quiet" id="sessions-revoke-all">Sign out everywhere</button>
162
172
  <span class="settings-card__hint">ends every session including this one — you will be asked to sign in again.</span>
163
173
  </div>
164
174
  <p class="section-note">Ending a session takes effect immediately; the token stops working on its very next request.</p>
@@ -213,11 +223,11 @@
213
223
  <div class="settings-card">
214
224
  <a class="settings-btn" href="/downloads/devbox/mac-arm64">Download for Mac</a>
215
225
  <a class="settings-btn" href="/downloads/devbox/win-x64">Download for Windows</a>
216
- <span class="settings-card__hint">Intel Mac? <a href="/downloads/devbox/mac-x64">This one</a>.
217
- ARM Windows (Surface, Snapdragon, Parallels)? <a href="/downloads/devbox/win-arm64">This one</a>.</span>
218
- <!-- #924: latest-release courtesy line; populated from /downloads/devbox/version -->
219
- <span class="settings-card__hint" id="boxapp-latest" hidden></span>
220
226
  </div>
227
+ <p class="panel-hint">Intel Mac? <a href="/downloads/devbox/mac-x64">This one</a>.
228
+ ARM Windows (Surface, Snapdragon, Parallels)? <a href="/downloads/devbox/win-arm64">This one</a>.
229
+ <!-- #924: latest-release courtesy line; populated from /downloads/devbox/version -->
230
+ <span id="boxapp-latest" hidden></span></p>
221
231
  <p class="section-note">
222
232
  First open: your computer warns about an unknown developer — expected
223
233
  (we haven't bought the signing certificates yet; the app is ours).
@@ -252,7 +262,7 @@
252
262
  claimed task. It never limits the work on the task itself. Your rank
253
263
  sets the starting point; newcomers stay locked low.
254
264
  </p>
255
- <div class="sound-rows" id="wander-rows"></div>
265
+ <div class="prows" id="wander-rows" role="radiogroup" aria-labelledby="wandering-h"></div>
256
266
  <p class="settings-status" id="wandering-status" role="status" aria-live="polite"></p>
257
267
  <p class="section-note" id="wandering-note"></p>
258
268
  </section>
@@ -287,7 +297,7 @@
287
297
  <div class="voices-wrap">
288
298
  <table class="voices" id="voices-table">
289
299
  <thead>
290
- <tr><th>Skill</th><th>Default</th><th>Your choice</th></tr>
300
+ <tr><th scope="col">Skill</th><th scope="col">Default</th><th scope="col">Your choice</th></tr>
291
301
  </thead>
292
302
  <tbody id="voices-body"></tbody>
293
303
  </table>
@@ -305,9 +315,8 @@
305
315
  any you would rather not hear.
306
316
  </p>
307
317
  <div class="sound-volume" id="sound-volume" hidden>
308
- <span class="sound-volume__label">Volume</span>
309
- <input type="range" id="sound-volume-range" min="0" max="100" step="5" value="100"
310
- aria-label="Master sound volume">
318
+ <label class="field-label" for="sound-volume-range">Volume</label>
319
+ <input type="range" id="sound-volume-range" min="0" max="100" step="5" value="100">
311
320
  <span class="sound-volume__pct" id="sound-volume-pct">100%</span>
312
321
  </div>
313
322
  <div class="sound-rows" id="sound-rows"></div>
@@ -360,7 +369,7 @@
360
369
  <script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
361
370
  <!-- #807: shared dev-box panel — loaded before settings.js so OTBBoxPanel exists. -->
362
371
  <script src="/builders/box-panel.js?v=2026-06-14-domutils"></script>
363
- <script src="/builders/settings.js?v=2026-07-10-regroup"></script>
372
+ <script src="/builders/settings.js?v=2026-09-02-panel"></script>
364
373
  <!-- task 1003341: the Active sessions panel. Its own file rather than more of
365
374
  settings.js, which sits close to the 1500-line size ratchet. -->
366
375
  <script src="/builders/settings-sessions.js?v=2026-08-29-sessions"></script>