@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
@@ -64,10 +64,16 @@
64
64
  // Colour AND word. A badge distinguished only by hue tells a colour-blind
65
65
  // reader nothing, and this badge decides how to read the whole page.
66
66
  const GRADE_WORD = { full: 'Full Idea', spark: 'Big Idea Spark', quick: 'Quick idea' };
67
+ // A grade classifies the record, which is the status vocabulary's job — the
68
+ // same job the task record's status pill does, so it is the same COMPONENT.
69
+ // `.rec-pill` in record.css is that component; a private copy in idea.css was
70
+ // a hundred lines of the archetype waiting to drift, which is the exact thing
71
+ // the shared sheet exists to prevent.
72
+ const GRADE_TONE = { full: 'ok', spark: 'warn', quick: 'info' };
67
73
 
68
74
  function gradeBadge(grade) {
69
75
  const g = GRADE_WORD[grade] ? grade : 'quick';
70
- return `<span class="ig-grade ig-grade--${escapeHtml(g)}">${escapeHtml(GRADE_WORD[g])}</span>`;
76
+ return `<span class="rec-pill rec-pill--${escapeHtml(GRADE_TONE[g])}">${escapeHtml(GRADE_WORD[g])}</span>`;
71
77
  }
72
78
 
73
79
  function scoreRow(score) {
@@ -213,8 +219,11 @@
213
219
  const grade = GRADE_WORD[idea.grade] ? idea.grade : 'quick';
214
220
  const parts = [];
215
221
 
216
- parts.push(`<div class="ig-head">${gradeBadge(grade)}</div>`);
217
- parts.push(`<h1 class="ig-title" id="idea-h">${escapeHtml(idea.title || `Idea ${idea.id}`)}</h1>`);
222
+ // The record's head, in the shared archetype: the kind eyebrow carries the
223
+ // grade badge the way the task record's carries its status, so the two pages
224
+ // open on the same line even though they hold different facts.
225
+ parts.push(`<p class="rec-kind">Idea ${gradeBadge(grade)}</p>`);
226
+ parts.push(`<h1 class="rec-title" id="idea-h"><span class="rec-title__id">${escapeHtml(String(idea.id))}</span>${escapeHtml(idea.title || 'Untitled idea')}</h1>`);
218
227
  parts.push(statusLine(idea));
219
228
  parts.push(credit(idea));
220
229
 
@@ -261,8 +270,12 @@
261
270
  if (btn) btn.addEventListener('click', () => { toggleMark(idea); });
262
271
  }
263
272
 
273
+ // The honest failure. It keeps the <h1> for the same reason the loading state
274
+ // does: a render is a render, and one-header-main-h1 measures the DOM it gets.
264
275
  function fail(msg) {
265
- $('#idea-body').innerHTML = `<p class="deeplink-card__title" id="idea-h">${escapeHtml(msg)}</p>`;
276
+ $('#idea-body').innerHTML =
277
+ `<p class="rec-kind">Idea</p><h1 class="rec-big" id="idea-h">${escapeHtml(msg)}</h1>` +
278
+ `<div class="rec-actions rec-sec"><a class="btn btn--ghost" href="${hallBase()}/ideas">Open the idea composer</a></div>`;
266
279
  $('#idea-sub').textContent = '';
267
280
  }
268
281
 
@@ -0,0 +1,14 @@
1
+ {
2
+ "_": "The hall's IDEA RECORD through modules/ui-design/kit/render.js (task 1003305). Same harness note as task.states.json: the idea's five answers, its completeness bar and its author-only mark control need a LOADED idea, so run it against the hall-preview harness:\n\n node scripts/hall-preview/server.js --port 4612 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/idea.states.json --base-in http://builders.localhost:4612 --base-out http://builders.localhost:4612",
3
+ "page": "/idea/12",
4
+ "surface": "hall-ui",
5
+ "stub": { "prefix": "/builders/" },
6
+ "modeQuery": false,
7
+ "ignoreRequests": ["/api/(gds|bongos)/"],
8
+ "ignoreConsole": ["/api/(gds|bongos)/", "\b401\b", "\b404\b", "Unauthorized", "Not Found", "load failed"],
9
+ "states": {
10
+ "record": { "auth": true, "actions": [["wait", 600]], "expect": { "visible": ["#idea-body", "#idea-h"] } },
11
+ "missing": { "auth": true, "url": "/idea/999999", "actions": [["wait", 600]], "expect": { "visible": ["#idea-h"] } }
12
+ },
13
+ "reducedMotion": { "auth": true, "actions": [["wait", 600]] }
14
+ }
@@ -1,145 +1,186 @@
1
- /* modules/hall-ui/public/ideas.css — the Ideas tab (task 1002928 / BV1.R152 of
2
- goal 1000062).
3
-
4
- Built on the hall's existing tokens (style.css), not a new palette. Only the
5
- shapes this page needs are here: a wide-screen two-column composer with the
6
- meter alongside, collapsing to one column where there is no room for it.
7
-
8
- USES THE REAL TOKEN NAMES — --border / --surface-2 / --accent / --ok / --warn /
9
- --danger / --radius, so every token below re-derives on its own and this page
10
- needs no theme-specific block at all. (The sibling trap this note used to warn
11
- about — copy-desk.css reaching for an undefined --line / --panel and getting a
12
- dark-ground fallback on the light theme — was fixed in task 1003303, when the
13
- chrome-world tier defined --line as a WIDTH and those borders would otherwise
14
- have gone invalid.) */
15
-
16
- /* The composer and its meter sit side by side once there is room. Below that
17
- width the meter stacks ABOVE the fields — a readout you cannot see while
18
- typing is not a live meter. */
19
- @media (min-width: 62rem) {
20
- .app-content > main { padding-right: 20rem; }
21
- .fi-meter {
22
- position: fixed;
23
- top: 6.5rem;
24
- right: 1.5rem;
25
- width: 17rem;
26
- max-height: calc(100vh - 8rem);
27
- overflow-y: auto;
28
- }
29
- }
30
-
1
+ /* ideas.css — the Ideas tab: the Full Idea composer, its live completeness meter
2
+ and the spark queue (task 1002928 / BV1.R152 of goal 1000062; re-skinned into
3
+ the chrome world by task 1003305, goal 1000081).
4
+
5
+ The composer is NOT a record, so it does not load record.css. What it is, is a
6
+ form beside a readout: the fields are the world's own field (the base
7
+ `select, input, textarea` rule in style.css), the meter is a panel on the
8
+ shell's right rail, and the queue is v1's bare ledger inside a v3 panel.
9
+
10
+ TWO THINGS THE RE-SKIN REMOVED, both of them structural rather than paint:
11
+
12
+ - THE SHELL OVERRIDE. This sheet used to set `.app-content > main
13
+ { padding-right: 20rem }` and pin the meter at `top: 6.5rem`. A page reaching
14
+ into shell layout is invisible from the shell, and the 6.5rem was a hand-copy
15
+ of the topbar height that nothing kept in step with `--topbar-h`. Both halves
16
+ now live in style.css as `.app-content--railed` + `.app-rail`, which the page
17
+ OPTS INTO from its markup. Do not re-paste the override.
18
+ - THE COMPAT ALIASES. --border → --rule / --rule-soft, --surface-2 → --glass.
19
+ They still exist for the pages nobody has re-skinned, so spending one here
20
+ would be legal CSS that quietly opts this sheet back out of the world.
21
+
22
+ The `opacity: 0.7`-style dimming this sheet used throughout is gone too: a
23
+ token says which ink it means (--ink-soft, --ink-faint) and survives a theme
24
+ flip, where an opacity on inherited ink is a different colour in each mode and
25
+ measures differently against the ground. */
26
+
27
+ /* ---- the composer form --------------------------------------------------- */
31
28
  .fi-label {
32
29
  display: block;
33
- margin: 1.1rem 0 0.3rem;
34
- font-size: 0.9rem;
35
- font-weight: 600;
30
+ margin: var(--sp-md) 0 6px;
31
+ font-family: var(--label-face);
32
+ font-size: var(--label-size);
33
+ font-weight: 400;
34
+ letter-spacing: var(--label-space);
35
+ text-transform: var(--label-case);
36
+ color: var(--ink-faint);
37
+ }
38
+ .fi-hint {
39
+ display: block;
40
+ margin-top: 4px;
41
+ font-family: var(--font-body);
42
+ font-size: 13px;
43
+ letter-spacing: normal;
44
+ text-transform: none;
45
+ color: var(--ink-faint);
36
46
  }
37
- .fi-hint { font-weight: 400; font-size: 0.8rem; opacity: 0.7; }
38
47
 
48
+ /* The base rule in style.css already carries the world's field — the hairline,
49
+ the pill radius, the ink. Only what a full-width multi-line field needs is
50
+ here; a textarea takes --radius-sm from the base rule, not the pill. */
39
51
  .fi-input,
40
52
  .fi-text {
41
53
  width: 100%;
42
- padding: 0.55rem 0.7rem;
43
- border: 1px solid var(--border);
44
- border-radius: var(--radius-sm);
45
- background: var(--surface-2);
46
- color: inherit;
47
- font: inherit;
54
+ max-width: var(--measure);
48
55
  line-height: 1.55;
49
56
  }
50
- .fi-text { resize: vertical; min-height: 5.5rem; }
51
- .fi-input:focus,
52
- .fi-text:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
57
+ .fi-text { resize: vertical; min-height: 6rem; padding: 10px 14px; }
58
+ /* The world's two-tone focus ring, the same one :focus-visible paints — a field
59
+ is not exempt from the indicator every other control gets. */
60
+ .fi-input:focus-visible,
61
+ .fi-text:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; box-shadow: 0 0 0 8px var(--bg); }
53
62
 
54
- .fi-fields { margin-top: 0.5rem; }
55
- .fi-field + .fi-field { margin-top: 0.35rem; }
63
+ .fi-fields { margin-top: var(--sp-xs); }
64
+ .fi-field + .fi-field { margin-top: 6px; }
56
65
 
57
- .fi-fieldnote { margin: 0.3rem 0 0; font-size: 0.78rem; opacity: 0.7; min-height: 1.1em; }
58
- .fi-fieldnote[data-ok="1"] { opacity: 0.85; color: var(--ok); }
66
+ /* The per-field note: how much more text this answer wants. It goes GREEN when
67
+ the field has cleared its floor — the status vocabulary, because "this answer
68
+ is complete enough" is verification state and not a live control. */
69
+ .fi-fieldnote { margin: 6px 0 0; font-size: 12.5px; color: var(--ink-faint); min-height: 1.1em; }
70
+ .fi-fieldnote[data-ok="1"] { color: var(--ok); }
59
71
 
60
- .fi-note { font-size: 0.85rem; opacity: 0.75; }
72
+ .fi-note { font-size: 13.5px; color: var(--ink-faint); }
61
73
 
62
- .fi-err {
63
- margin: 0.9rem 0 0;
64
- font-size: 0.87rem;
65
- line-height: 1.5;
66
- color: var(--danger);
67
- }
74
+ .fi-err { margin: var(--sp-sm) 0 0; max-width: var(--measure); font-size: 14px; line-height: 1.5; color: var(--danger); }
68
75
  .fi-err[data-visible="0"] { display: none; }
69
76
 
70
- .fi-actions {
71
- display: flex;
72
- flex-wrap: wrap;
73
- gap: 0.6rem 0.75rem;
74
- align-items: center;
75
- margin-top: 1.2rem;
76
- }
77
- .fi-draft { font-size: 0.8rem; opacity: 0.7; }
78
-
79
- /* ---- the meter ---------------------------------------------------------- */
77
+ .fi-actions { display: flex; flex-wrap: wrap; gap: 10px 12px; align-items: center; margin-top: var(--sp-md); }
78
+ .fi-draft { font-size: 12.5px; color: var(--ink-faint); }
80
79
 
80
+ /* ---- the meter ----------------------------------------------------------- */
81
+ /* A panel like any other in v3: --bg-card at the full radius, tone doing the
82
+ separation, no drawn edge. Its position is the shell's (.app-rail) — this
83
+ sheet says what it LOOKS like, never where it sits. */
81
84
  .fi-meter {
82
- border: 1px solid var(--border);
85
+ background: var(--bg-card);
86
+ border: var(--line) solid transparent;
83
87
  border-radius: var(--radius);
84
- background: var(--surface-2);
85
- padding: 0.9rem 1rem 1rem;
86
- margin: 1.5rem;
88
+ padding: var(--sp-sm) var(--sp-sm) var(--sp-md);
89
+ }
90
+ .fi-meter__h {
91
+ margin: 0 0 var(--sp-xs);
92
+ font-family: var(--label-face);
93
+ font-size: var(--label-size);
94
+ font-weight: 400;
95
+ letter-spacing: var(--label-space);
96
+ text-transform: var(--label-case);
97
+ color: var(--ink-faint);
87
98
  }
88
- .fi-meter__h { margin: 0 0 0.6rem; font-size: 0.95rem; }
89
99
 
90
- .fi-gauge { display: flex; align-items: center; gap: 0.6rem; }
100
+ .fi-gauge { display: flex; align-items: baseline; gap: 12px; }
91
101
  .fi-gauge__track {
92
102
  flex: 1;
93
- height: 0.55rem;
94
- border-radius: 0.3rem;
95
- background: var(--border);
103
+ align-self: center;
104
+ height: 6px;
105
+ border-radius: 3px;
106
+ background: var(--skeleton);
96
107
  overflow: hidden;
97
108
  }
109
+ /* The three bands describe the TEXT, not a verdict — the pass bar lives in the
110
+ economy module and this readout deliberately does not know it. State colours,
111
+ never the accent: nothing here is pressable or live. */
98
112
  .fi-gauge__fill {
99
113
  height: 100%;
100
114
  width: 0;
101
- border-radius: 0.3rem;
115
+ border-radius: 3px;
116
+ background: var(--info);
102
117
  transition: width 0.18s ease-out;
103
- background: var(--accent);
104
118
  }
105
- /* Three bands describing the TEXT, not a verdict — the pass bar lives in the
106
- economy module and this readout deliberately does not know it. */
107
119
  .fi-gauge__fill[data-band="thin"] { background: var(--danger); }
108
120
  .fi-gauge__fill[data-band="part"] { background: var(--warn); }
109
121
  .fi-gauge__fill[data-band="full"] { background: var(--ok); }
110
- .fi-gauge__n { margin: 0; font-size: 0.9rem; font-variant-numeric: tabular-nums; min-width: 4.2rem; text-align: right; }
111
-
112
- .fi-meter__list { list-style: none; margin: 0.85rem 0 0; padding: 0; display: grid; gap: 0.45rem; }
113
- .fi-mrow { display: grid; gap: 0.2rem; }
114
- .fi-mrow__l { font-size: 0.76rem; opacity: 0.8; line-height: 1.3; }
115
- .fi-mrow__bar { display: block; height: 0.3rem; border-radius: 0.2rem; background: var(--border); overflow: hidden; }
116
- .fi-mrow__fill { display: block; height: 100%; width: 0; border-radius: 0.2rem; background: var(--accent); transition: width 0.18s ease-out; }
117
-
118
- .fi-meter__note { margin: 0.9rem 0 0; font-size: 0.76rem; opacity: 0.65; line-height: 1.5; }
119
-
120
- /* ---- the spark queue + develop mode (task 1002930 / R154) --------------- */
122
+ /* The figure takes the display face at 300 with tabular numerals, so a live
123
+ re-score cannot reflow the row it sits in (DESIGN.md, The Tabular Rule). */
124
+ .fi-gauge__n {
125
+ margin: 0;
126
+ font-family: var(--font-display);
127
+ font-weight: 300;
128
+ font-size: 22px;
129
+ line-height: 1;
130
+ letter-spacing: -0.03em;
131
+ color: var(--ink);
132
+ font-variant-numeric: tabular-nums;
133
+ min-width: 4.2rem;
134
+ text-align: right;
135
+ }
121
136
 
122
- .fi-queue { display: grid; gap: 10px; }
137
+ .fi-meter__list { list-style: none; margin: var(--sp-sm) 0 0; padding: 0; display: grid; gap: 8px; }
138
+ .fi-mrow { display: grid; gap: 4px; }
139
+ /* --ink-soft, not --ink-faint: these five are the questions themselves, and on
140
+ the dark card the faint tier left the whole readout illegible at a glance
141
+ even though the pair clears AA. */
142
+ .fi-mrow__l { font-size: 12px; line-height: 1.3; color: var(--ink-soft); }
143
+ .fi-mrow__bar { display: block; height: 4px; border-radius: 2px; background: var(--skeleton); overflow: hidden; }
144
+ .fi-mrow__fill { display: block; height: 100%; width: 0; border-radius: 2px; background: var(--info); transition: width 0.18s ease-out; }
145
+
146
+ .fi-meter__note { margin: var(--sp-sm) 0 0; font-size: 12px; line-height: 1.5; color: var(--ink-faint); }
147
+
148
+ /* ---- the spark queue + develop mode (task 1002930 / R154) ---------------- */
149
+ /* v1's bare ledger inside a v3 panel: a hairline on top, air, and the first row
150
+ drops both. It used to be a stack of bordered wells, which in v3 is a card
151
+ inside a card — the treatment the owner's pick removed. */
152
+ .fi-queue { display: grid; }
123
153
  .fi-spark {
124
- display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: baseline;
125
- padding: 12px 14px;
126
- border: 1px solid var(--border); border-radius: var(--radius-sm);
127
- background: var(--surface-2);
154
+ display: flex;
155
+ flex-wrap: wrap;
156
+ gap: 6px 14px;
157
+ align-items: baseline;
158
+ border-top: var(--line) solid var(--rule-soft);
159
+ padding: 14px 0;
128
160
  }
129
- .fi-spark__title { margin: 0; font-weight: 600; font-size: 0.92rem; flex: 1 1 20rem; }
130
- .fi-spark__title a { color: inherit; }
131
- .fi-spark__who { font-size: 0.8rem; color: var(--ink-faint); }
132
- .fi-spark__go { font-size: 0.84rem; white-space: nowrap; }
133
- .fi-queue-empty { font-size: 0.88rem; color: var(--ink-faint); }
134
-
135
- /* The spark being developed. Bordered on the leading edge rather than boxed: it
136
- is context for the fields below it, not a competing card. */
161
+ .fi-spark:first-child { border-top: 0; padding-top: 0; }
162
+ .fi-spark__title { margin: 0; flex: 1 1 20rem; font-size: 14.5px; color: var(--ink); }
163
+ .fi-spark__title a { display: inline-block; min-height: 24px; padding: 3px 0; line-height: 18px; color: inherit; }
164
+ .fi-spark__who { font-size: 12.5px; color: var(--ink-faint); }
165
+ .fi-spark__go { flex: none; white-space: nowrap; }
166
+ .fi-queue-empty { font-size: 13.5px; color: var(--ink-faint); }
167
+
168
+ /* The spark being developed. A band on the leading edge rather than a box: it is
169
+ context for the fields below it, not a competing card. Amber because a spark
170
+ is an idea awaiting work, which is what --warn means in this vocabulary. */
137
171
  .fi-develop {
138
- margin: 0 0 6px;
139
- padding: 2px 0 2px 14px;
172
+ margin: 0 0 var(--sp-xs);
173
+ padding: 2px 0 2px var(--sp-sm);
140
174
  border-left: 3px solid var(--warn);
141
175
  }
142
- .fi-develop__label { margin: 0; font-size: 0.76rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--warn); }
143
- .fi-develop__title { margin: 4px 0 0; font-weight: 600; }
144
- .fi-develop__body { margin: 4px 0 0; max-width: 70ch; line-height: 1.6; white-space: pre-wrap; color: var(--ink-soft); font-size: 0.9rem; }
145
- .fi-develop__who { margin: 6px 0 0; font-size: 0.8rem; color: var(--ink-faint); }
176
+ .fi-develop__label {
177
+ margin: 0;
178
+ font-family: var(--label-face);
179
+ font-size: var(--label-size);
180
+ letter-spacing: var(--label-space);
181
+ text-transform: var(--label-case);
182
+ color: var(--warn);
183
+ }
184
+ .fi-develop__title { margin: 6px 0 0; font-size: 15px; font-weight: 500; color: var(--ink); }
185
+ .fi-develop__body { margin: 6px 0 0; max-width: var(--measure); font-size: 14px; line-height: 1.6; color: var(--ink-soft); white-space: pre-wrap; }
186
+ .fi-develop__who { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-faint); }
@@ -18,8 +18,18 @@
18
18
  <div class="app-scrim" id="app-scrim" hidden></div>
19
19
  <div class="app-body">
20
20
  <header class="app-topbar" id="app-topbar"></header>
21
- <div class="app-content">
22
- <div class="page-head"><p class="page-head__sub" id="fi-sub">Loading the idea template…</p></div>
21
+ <!-- --railed reserves the room the meter occupies (style.css, "the right
22
+ rail"). This page used to take that room by overriding
23
+ `.app-content > main` from its own sheet, which is a page editing shell
24
+ layout — invisible from the shell, and it hard-coded a topbar height. -->
25
+ <div class="app-content app-content--railed">
26
+ <!-- The page's own name, in the LABEL voice — the display face is saved for
27
+ section headings (the work.html precedent, task 1003304). The page had
28
+ no h1 at all, so it failed one-header-main-h1 on every render. -->
29
+ <div class="page-head page-head--board">
30
+ <h1 class="page-head__h">Ideas</h1>
31
+ <p class="page-head__sub" id="fi-sub">Loading the idea template…</p>
32
+ </div>
23
33
 
24
34
  <main id="hall-main">
25
35
  <!-- The spark queue (task 1002930 / R154). ABOVE the composer, because
@@ -91,9 +101,9 @@
91
101
  </div>
92
102
 
93
103
  <!-- The meter rides along beside the form on a wide screen and above it on a
94
- narrow one (CSS decides). It is a READOUT, never an input: every number in
95
- it comes from the server's own scorer. -->
96
- <aside class="fi-meter" id="fi-meter" aria-labelledby="fi-meter-h" hidden>
104
+ narrow one (the shell's .app-rail decides). It is a READOUT, never an input:
105
+ every number in it comes from the server's own scorer. -->
106
+ <aside class="fi-meter app-rail" id="fi-meter" aria-labelledby="fi-meter-h" hidden>
97
107
  <h2 class="fi-meter__h" id="fi-meter-h">Completeness</h2>
98
108
  <div class="fi-gauge">
99
109
  <div class="fi-gauge__track"><div class="fi-gauge__fill" id="fi-gauge-fill"></div></div>
@@ -0,0 +1,15 @@
1
+ {
2
+ "_": "The hall's IDEA COMPOSER through modules/ui-design/kit/render.js (task 1003305). The five questions are rendered from GET /inbox/template and the spark queue from GET /inbox/sparks, so the populated form needs the hall-preview harness; the kit's own stub answers neither and renders the honest `could not load the idea template` line instead, which is the `no-template` state below.\n\n node scripts/hall-preview/server.js --port 4612 --fixture-me\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/ideas.states.json --base-in http://builders.localhost:4612 --base-out http://builders.localhost:4612\n\nThe right rail is the shell's `.app-content--railed` reserve, so the 62rem breakpoint is exercised at 1440 and stacked at 390/320 — which is the whole reason all three widths are rendered.",
3
+ "page": "/ideas",
4
+ "surface": "hall-ui",
5
+ "stub": { "prefix": "/builders/" },
6
+ "modeQuery": false,
7
+ "ignoreRequests": ["/api/(gds|bongos)/"],
8
+ "_console": "The 501 is the harness, not the page: the meter re-scores through POST /inbox/score on every keystroke and scripts/hall-preview/server.js answers every write with preview_readonly by design. Declared rather than hidden.",
9
+ "ignoreConsole": ["/api/(gds|bongos)/", "\b401\b", "\b404\b", "\b501\b", "Unauthorized", "Not Found", "Not Implemented", "load failed"],
10
+ "states": {
11
+ "compose": { "auth": true, "actions": [["wait", 700]], "expect": { "visible": ["#fi-form", "#fi-fields", "#fi-queue"] } },
12
+ "develop": { "auth": true, "url": "/ideas?develop=1000884", "actions": [["wait", 700]], "expect": { "visible": ["#fi-develop"] } }
13
+ },
14
+ "reducedMotion": { "auth": true, "actions": [["wait", 700]] }
15
+ }