@bongos/core 1.21.166 → 1.21.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +153 -73
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +8 -0
- package/clients/bongos-client/index.cjs +8 -0
- package/clients/bongos-client/index.d.ts +13 -0
- package/clients/bongos-client/index.mjs +8 -0
- package/docs/api/openapi.json +306 -3
- package/docs/api-reference.md +7 -3
- package/docs/copy-inventory.md +21 -20
- package/docs/copy-registry.json +34 -25
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +1 -0
- package/docs/page-inventory.json +3 -0
- package/docs/page-readings.json +445 -445
- package/modules/autonomy/governor-docket.js +10 -5
- package/modules/builder-settings/builder-needs.js +29 -3
- package/modules/copy-desk/guarded-lines.js +89 -0
- package/modules/copy-desk/guarded-lines.json +14 -0
- package/modules/copy-desk/module.json +2 -2
- package/modules/copy-desk/page-status.js +77 -7
- package/modules/copy-desk/pages.js +4 -0
- package/modules/copy-desk/pollers/stuck-page-digest.js +34 -0
- package/modules/copy-desk/routes/copy-desk.js +8 -0
- package/modules/copy-desk/stuck-tweaks.js +79 -0
- package/modules/copy-desk/tests/copy_no_cms.mjs +6 -1
- package/modules/copy-desk/tests/copy_page_status.mjs +2 -2
- package/modules/government/asks-db.js +38 -2
- package/modules/government/catalog.js +1 -1
- package/modules/government/docket.js +20 -2
- package/modules/government/migrations/government_032_ask_flags.sql +35 -0
- package/modules/government/routes/government.js +43 -1
- package/modules/hall-ui/public/approval-queue-lib.js +4 -0
- package/modules/hall-ui/public/approval-queue.js +1 -0
- package/modules/hall-ui/public/brand-apply.js +3 -0
- package/modules/hall-ui/public/city-decide.js +642 -0
- package/modules/hall-ui/public/city-draw.js +14 -3
- package/modules/hall-ui/public/city-switchboard.js +141 -0
- package/modules/hall-ui/public/city.css +176 -10
- package/modules/hall-ui/public/city.html +8 -3
- package/modules/hall-ui/public/city.js +185 -38
- package/modules/hall-ui/public/sky-data.js +4 -1
- package/modules/hall-ui/public/tweak-editor-lib.js +21 -2
- package/modules/hall-ui/public/tweak-editor.css +2 -0
- package/modules/hall-ui/public/tweak-editor.js +3 -1
- package/modules/lifecycle/db-claims.js +20 -5
- package/modules/lifecycle/rebase-gate.js +78 -0
- package/modules/lifecycle/routes/claims.js +10 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +28 -0
- package/scripts/gds/ask.js +68 -1
- package/scripts/gds/claim.js +6 -1
- package/scripts/gds/copy-apply.js +2 -0
- package/src/bongos/module-promotion.js +219 -0
- package/src/bongos/route-rank-check.js +7 -0
- package/src/bongos/routes/me.js +11 -0
- package/src/bongos/routes/modules.js +46 -0
- package/src/module-api.js +1 -1
- package/src/platform-server.js +5 -0
- package/tests/claim_gate_ci_unblock.mjs +4 -0
- package/tests/claim_gate_rebase.mjs +56 -3
- package/tests/copy_desk_page_editor.mjs +1 -1
- package/tests/copy_desk_page_submit.mjs +42 -0
- package/tests/copy_guarded_lines.mjs +54 -0
- package/tests/copy_stuck_page_tweaks.mjs +118 -0
- package/tests/government_ask_flags.mjs +80 -0
- package/tests/government_seed.mjs +1 -0
- package/tests/government_treasury.mjs +1 -0
- package/tests/governor_docket.mjs +1 -1
- package/tests/hall_approval_queue.mjs +15 -0
- package/tests/hall_city.mjs +5 -4
- package/tests/hall_city_living.mjs +118 -12
- package/tests/hall_city_rewording.mjs +51 -0
- package/tests/hall_city_switchboard.mjs +63 -0
- package/tests/hall_gov_real_site.mjs +2 -2
- package/tests/hall_sky.mjs +18 -0
- package/tests/hall_street_deck.mjs +6 -4
- package/tests/hall_street_depth.mjs +1 -1
- package/tests/hall_street_desk.mjs +5 -3
- package/tests/hall_tweak_editor.mjs +26 -0
- package/tests/module_promotion.mjs +290 -0
- package/tests/rebase_gate_set_aside.mjs +73 -0
- package/tests/reward_mode_surfacing.mjs +12 -0
|
@@ -766,6 +766,17 @@
|
|
|
766
766
|
let n = 0;
|
|
767
767
|
CIVIC_SLOTS.forEach((s) => {
|
|
768
768
|
const b = living.byKey[s[0]];
|
|
769
|
+
// Automation is a switchboard (owner, 2026-10-23): its marker is a switch,
|
|
770
|
+
// on or off, never a count of asks; it opens the board
|
|
771
|
+
if (s[0] === 'automation') {
|
|
772
|
+
const fence = living.city && living.city.fence;
|
|
773
|
+
const on = !!(fence && fence.enabled);
|
|
774
|
+
const at = P(s[1] + 1, s[2] + 1, civicTop[s[0]] + 8);
|
|
775
|
+
const nm = (b && b.name) || 'Automation';
|
|
776
|
+
pins.push({ key: 'switchboard', building: s[0], state: 'switch', on: on, count: 0, matters: [], title: 'the switchboard', aria: nm + ': switchboard, AI building: ' + (on ? 'on' : 'off'), x: r1(at[0] - 15), y: r1(at[1] - 52), h: 52, gf: null, gl: null, delay: -(n * 0.9), age: null, oldest_days: null });
|
|
777
|
+
n += 1;
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
769
780
|
const v = asksAt(b, answered);
|
|
770
781
|
if (!v.all.length) return;
|
|
771
782
|
let tier, list;
|
|
@@ -827,7 +838,7 @@
|
|
|
827
838
|
const r = ((b && b.readings) || []).find((x) => x && x.status === 'live' && x.figure);
|
|
828
839
|
if (r) return { text: String(r.figure), line: String(r.line || '') };
|
|
829
840
|
const fence = living.city && living.city.fence;
|
|
830
|
-
if (b && b.key === 'automation' && fence) return { text: fence.enabled ? '
|
|
841
|
+
if (b && b.key === 'automation' && fence) return { text: fence.enabled ? 'AI building: on' : 'AI building: off', line: '' };
|
|
831
842
|
if (b && b.agents > 0) return { text: b.agents + ' ' + words('agents_at_work', b.agents), line: '' };
|
|
832
843
|
if (b && b.decision && b.decision.rule_words) return { text: String(b.decision.rule_words), line: '' };
|
|
833
844
|
return { text: 'quiet', line: '' };
|
|
@@ -862,8 +873,8 @@
|
|
|
862
873
|
}
|
|
863
874
|
function ctaFor(onYou) {
|
|
864
875
|
return onYou > 0
|
|
865
|
-
? { label: 'decide ' + onYou + ' in a row', href:
|
|
866
|
-
: { label: 'start governing', href:
|
|
876
|
+
? { label: 'decide ' + onYou + ' in a row', href: '#decide', aria: 'Decide the ' + onYou + ' questions on you, one card at a time' }
|
|
877
|
+
: { label: 'start governing', href: '#decide', aria: 'Start governing: everything that waits, one card at a time' };
|
|
867
878
|
}
|
|
868
879
|
function livingLine(onYou, others, agents) {
|
|
869
880
|
const parts = [onYou ? onYou + ' ' + words('on_you', onYou) : 'nothing to do'];
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// modules/hall-ui/public/city-switchboard.js — AUTOMATION AS A SWITCHBOARD
|
|
2
|
+
// (owner, 2026-10-23): the Automation building's card is a board of switches,
|
|
3
|
+
// not a queue of asks. Unattended building is a standing state, so it never
|
|
4
|
+
// counts as a to-do (modules/autonomy/governor-docket.js settles the fence
|
|
5
|
+
// matter); what the viewer may change is drawn here as switches.
|
|
6
|
+
//
|
|
7
|
+
// ONLY THE SWITCHES YOU CONTROL. Every row comes from the Automation desks the
|
|
8
|
+
// docket hands THIS viewer (GovDesk.rowsFor: automation.switch, .goals,
|
|
9
|
+
// .runners), and the server decides those rows and their acts per viewer from
|
|
10
|
+
// the switch's own permission. So the board never draws a switch the server
|
|
11
|
+
// would refuse; a viewer who controls none is told who does.
|
|
12
|
+
//
|
|
13
|
+
// Each flip sends the desk row's own request (GovMatterCard.request) through
|
|
14
|
+
// the page's sender, then the page re-reads. No innerHTML.
|
|
15
|
+
(function () {
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
var FLOORS = [
|
|
19
|
+
{ floor: 0, title: 'AI builds on its own (Autobongos)', sub: 'On: AI agents pick up tasks and build them by themselves, even overnight. Off: nothing is built unless a person starts it.' },
|
|
20
|
+
{ floor: 1, title: 'Goals the AI may work on', sub: 'Turn a goal on to let the AI build it by itself. Goals left off are never touched.' },
|
|
21
|
+
{ floor: 2, title: 'Computers doing the building', sub: 'Each builder\'s computer that runs the AI. Pause one without stopping the rest.' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function str(v) { return v == null ? '' : String(v); }
|
|
25
|
+
|
|
26
|
+
// The board as data, for one viewer. Pure over the docket.
|
|
27
|
+
function model(docket, ctx) {
|
|
28
|
+
var D = window.GovDesk;
|
|
29
|
+
var c = ctx || {};
|
|
30
|
+
if (!D || !D.rowsFor || !docket) return { groups: [], any: false };
|
|
31
|
+
var groups = FLOORS.map(function (f) {
|
|
32
|
+
var rows = D.rowsFor('automation', f.floor, docket, { now: c.now || Date.now(), viewerId: c.viewerId, goals: c.goals || [] });
|
|
33
|
+
var switches = [];
|
|
34
|
+
rows.forEach(function (r) {
|
|
35
|
+
var keys = r.actions.map(function (a) { return a.key; });
|
|
36
|
+
var choices = r.choices || {};
|
|
37
|
+
if (keys.indexOf('switch_on') >= 0) switches.push({ id: r.key, name: 'For the whole project', on: false, fact: firstFact(r), flip: { row: r, key: 'switch_on', input: {} } });
|
|
38
|
+
else if (keys.indexOf('switch_off') >= 0) switches.push({ id: r.key, name: 'For the whole project', on: true, fact: firstFact(r), flip: { row: r, key: 'switch_off', reasons: (choices.switch_off || {}).options || [] } });
|
|
39
|
+
else if (keys.indexOf('allow') >= 0) {
|
|
40
|
+
// the "allow a goal" row: every open goal not yet allowed is an OFF switch
|
|
41
|
+
((choices.allow || {}).options || []).forEach(function (o) {
|
|
42
|
+
switches.push({ id: r.key + ':' + o.key, name: str(o.input && o.input.label) || o.label, on: false, fact: 'off: the AI leaves it alone', flip: { row: r, key: 'allow', input: o.input } });
|
|
43
|
+
});
|
|
44
|
+
} else if (keys.indexOf('disallow') >= 0) {
|
|
45
|
+
var first = keys.indexOf('first') < 0;
|
|
46
|
+
switches.push({ id: r.key, name: r.name, on: true, fact: first ? 'on, and worked first' : 'on: the AI may build it', first: first, flip: { row: r, key: 'disallow', input: {} }, star: first ? null : { row: r, key: 'first', input: {} } });
|
|
47
|
+
} else if (keys.indexOf('pause') >= 0) switches.push({ id: r.key, name: r.name, on: true, fact: firstFact(r), flip: { row: r, key: 'pause', reasons: (choices.pause || {}).options || [] } });
|
|
48
|
+
else if (keys.indexOf('resume') >= 0) switches.push({ id: r.key, name: r.name, on: false, fact: firstFact(r) || 'paused', flip: { row: r, key: 'resume', input: {} } });
|
|
49
|
+
});
|
|
50
|
+
return { title: f.title, sub: f.sub, switches: switches };
|
|
51
|
+
}).filter(function (g) { return g.switches.length; });
|
|
52
|
+
return { groups: groups, any: groups.length > 0 };
|
|
53
|
+
}
|
|
54
|
+
function firstFact(r) { return str(r.fact) || (r.facts && r.facts[0]) || ''; }
|
|
55
|
+
|
|
56
|
+
// Draw the board into `host`. on { send(req) -> Promise<{ok,status,body}>, done(toast, ok), busy }
|
|
57
|
+
function draw(doc, host, docket, ctx, on) {
|
|
58
|
+
var h = function (tag, cls, text) { var n = doc.createElement(tag); if (cls) n.className = cls; if (text != null) n.textContent = String(text); return n; };
|
|
59
|
+
var m = model(docket, ctx);
|
|
60
|
+
var board = h('div', 'swb');
|
|
61
|
+
if (!m.any) {
|
|
62
|
+
var b = (docket && docket.buildings || []).filter(function (x) { return x && x.key === 'automation'; })[0];
|
|
63
|
+
var who = b && b.decision && b.decision.who ? b.decision.who : 'whoever may turn the AI building on and off';
|
|
64
|
+
board.appendChild(h('p', 'swb__none', 'None of these switches are yours. They belong to ' + who + '.'));
|
|
65
|
+
host.appendChild(board);
|
|
66
|
+
return m;
|
|
67
|
+
}
|
|
68
|
+
var open = null; // the switch waiting on a reason
|
|
69
|
+
function send(flip, input) {
|
|
70
|
+
var C = window.GovMatterCard;
|
|
71
|
+
var req = C && C.request ? C.request(flip.row.card, flip.key, input || flip.input || {}) : null;
|
|
72
|
+
if (!req) { on.done('That switch cannot be flipped from here.', false); return; }
|
|
73
|
+
on.send(req).then(function (res) {
|
|
74
|
+
var ok = res && res.ok;
|
|
75
|
+
var preview = res && res.status === 501 && res.body && res.body.error && res.body.error.code === 'preview_readonly';
|
|
76
|
+
var toast = ok ? (C.answer(flip.row.card, flip.key, res.body).toast || 'Done.') : preview ? 'Sent. This preview stores nothing.' : C.refusal(res.status, res.body);
|
|
77
|
+
on.done(toast, ok || preview);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
m.groups.forEach(function (g) {
|
|
81
|
+
var sec = h('section', 'swb__group');
|
|
82
|
+
var head = h('div', 'swb__head');
|
|
83
|
+
head.appendChild(h('h4', 'swb__title', g.title));
|
|
84
|
+
head.appendChild(h('span', 'swb__sub', g.sub));
|
|
85
|
+
sec.appendChild(head);
|
|
86
|
+
g.switches.forEach(function (s) {
|
|
87
|
+
var row = h('div', 'swb__row' + (s.on ? ' swb__row--on' : ''));
|
|
88
|
+
var label = h('div', 'swb__label');
|
|
89
|
+
label.appendChild(h('span', 'swb__name', s.name));
|
|
90
|
+
if (s.fact) label.appendChild(h('span', 'swb__fact', s.fact));
|
|
91
|
+
row.appendChild(label);
|
|
92
|
+
if (s.star) {
|
|
93
|
+
var star = h('button', 'swb__star', 'do this first');
|
|
94
|
+
star.setAttribute('type', 'button');
|
|
95
|
+
star.setAttribute('title', 'Work this goal first');
|
|
96
|
+
if (on.busy) star.setAttribute('disabled', '');
|
|
97
|
+
star.addEventListener('click', function () { send(s.star); });
|
|
98
|
+
row.appendChild(star);
|
|
99
|
+
}
|
|
100
|
+
var t = h('button', 'swb__toggle');
|
|
101
|
+
t.setAttribute('type', 'button');
|
|
102
|
+
t.setAttribute('role', 'switch');
|
|
103
|
+
t.setAttribute('aria-checked', s.on ? 'true' : 'false');
|
|
104
|
+
t.setAttribute('aria-label', s.name + ': ' + (s.on ? 'on' : 'off'));
|
|
105
|
+
if (on.busy) t.setAttribute('disabled', '');
|
|
106
|
+
t.appendChild(h('span', 'swb__knob'));
|
|
107
|
+
t.appendChild(h('span', 'swb__state', s.on ? 'on' : 'off'));
|
|
108
|
+
row.appendChild(t);
|
|
109
|
+
sec.appendChild(row);
|
|
110
|
+
// turning something off asks why, in one tap
|
|
111
|
+
var why = null;
|
|
112
|
+
if (s.flip.reasons && s.flip.reasons.length) {
|
|
113
|
+
why = h('div', 'swb__why');
|
|
114
|
+
why.setAttribute('hidden', '');
|
|
115
|
+
why.appendChild(h('span', 'swb__why-ask', 'why?'));
|
|
116
|
+
s.flip.reasons.forEach(function (o) {
|
|
117
|
+
var c = h('button', 'swb__chip', o.label);
|
|
118
|
+
c.setAttribute('type', 'button');
|
|
119
|
+
c.addEventListener('click', function () { send(s.flip, o.input); });
|
|
120
|
+
why.appendChild(c);
|
|
121
|
+
});
|
|
122
|
+
sec.appendChild(why);
|
|
123
|
+
}
|
|
124
|
+
t.addEventListener('click', function () {
|
|
125
|
+
if (why) {
|
|
126
|
+
if (open && open !== why) open.setAttribute('hidden', '');
|
|
127
|
+
if (why.hasAttribute('hidden')) { why.removeAttribute('hidden'); open = why; var f = why.querySelector('.swb__chip'); if (f && f.focus) f.focus(); } else why.setAttribute('hidden', '');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
send(s.flip);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
board.appendChild(sec);
|
|
134
|
+
});
|
|
135
|
+
board.appendChild(h('p', 'swb__note', 'Only the switches you control are shown.'));
|
|
136
|
+
host.appendChild(board);
|
|
137
|
+
return m;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
window.GovCitySwitchboard = { model: model, draw: draw, FLOORS: FLOORS };
|
|
141
|
+
}());
|
|
@@ -218,17 +218,33 @@ html[data-fullscreen="on"] .city-top { right: 184px; }
|
|
|
218
218
|
glass and its tokens street-deck.css's (the ask inside is the deck's card) */
|
|
219
219
|
.city-card { position: absolute; left: 50%; top: 96px; z-index: 8; width: min(432px, calc(100% - 32px)); max-height: calc(100% - 80px); overflow-y: auto; box-sizing: border-box; display: flex; flex-direction: column; gap: 16px; padding: 22px 24px 18px; border-radius: 28px; color: var(--ink); }
|
|
220
220
|
.city-card[hidden] { display: none; }
|
|
221
|
-
.city-
|
|
222
|
-
.city-
|
|
223
|
-
.city-
|
|
224
|
-
.city-
|
|
221
|
+
.city-card__top { display: flex; align-items: baseline; gap: 10px; }
|
|
222
|
+
.city-card__name { flex: 1; min-width: 0; margin: 0; font-size: 22px; font-weight: 400; letter-spacing: -0.02em; }
|
|
223
|
+
.city-card__counts { flex: none; font-size: 12.5px; color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
224
|
+
.city-card__counts b { font-weight: 500; color: var(--ink); }
|
|
225
|
+
.city-card__count--you, .city-card__counts b.city-card__count--you { color: var(--accent); }
|
|
225
226
|
.city-card__f { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink-soft); }
|
|
226
|
-
.city-
|
|
227
|
-
|
|
228
|
-
.city-
|
|
229
|
-
|
|
230
|
-
.city-
|
|
231
|
-
.city-
|
|
227
|
+
.city-card__said { margin: -4px 0 0; font-size: 13px; line-height: 1.45; color: var(--ink-soft); }
|
|
228
|
+
/* a building that waits on you wears the project colour, and glows it */
|
|
229
|
+
.city-card.city-card--you.gov-glass { border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent); background: color-mix(in srgb, var(--accent) 14%, var(--bg-card)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent), 0 0 38px color-mix(in srgb, var(--accent) 45%, transparent); }
|
|
230
|
+
/* the ask inside: a smaller question, its answers inside the card, no "only you" line (the glow says it) */
|
|
231
|
+
.city-card .city-ask.ask { padding: 14px 16px; gap: 10px; }
|
|
232
|
+
.city-card .city-ask .ask__q { font-size: 17px; line-height: 1.3; font-weight: 400; }
|
|
233
|
+
.city-card .city-ask .ask__said { font-size: 13px; }
|
|
234
|
+
.city-card .city-ask .ask__opt { min-height: 44px; padding: 6px 12px 6px 10px; border-radius: 14px; }
|
|
235
|
+
.city-card .city-ask .ask__label { font-size: 14px; }
|
|
236
|
+
.city-card .city-ask .ask__result { font-size: 12px; }
|
|
237
|
+
.city-card .city-ask .ask__foot { font-size: 12px; }
|
|
238
|
+
.city-card__acts { display: flex; align-items: center; gap: 8px; }
|
|
239
|
+
.city-card__gap { flex: 1; }
|
|
240
|
+
.city-card__arrow { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-size: 18px; line-height: 1; cursor: pointer; }
|
|
241
|
+
.city-card__arrow:hover { background: var(--gov-chip-pick); }
|
|
242
|
+
.city-card__go { display: inline-flex; align-items: center; height: 34px; margin-left: 6px; padding: 0 16px; box-sizing: border-box; border: 0; border-radius: 999px; font-family: var(--font-body); font-size: 13.5px; cursor: pointer; background: var(--ink); color: var(--bg); }
|
|
243
|
+
.city-card--you .city-card__go { background: var(--accent); color: var(--accent-on); }
|
|
244
|
+
.city-card__close { flex: none; display: inline-flex; align-items: center; justify-content: center; background: none; border: 0; padding: 0; min-width: 24px; min-height: 24px; cursor: pointer; opacity: .6; }
|
|
245
|
+
.city-card__close kbd { font-size: 10px; padding: 1px 4px; }
|
|
246
|
+
.city-card__close:hover { opacity: 1; }
|
|
247
|
+
.city-card__close:focus-visible, .city-card__go:focus-visible, .city-card__arrow:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
232
248
|
.city-spot { z-index: 7; }
|
|
233
249
|
|
|
234
250
|
@media (max-width: 640px) {
|
|
@@ -285,3 +301,153 @@ html[data-fullscreen="on"] .city-top { right: 184px; }
|
|
|
285
301
|
body[data-page="city"] *, body[data-page="city"] *::before, body[data-page="city"] *::after { animation: none !important; transition: none !important; }
|
|
286
302
|
.city-parcels { display: none; }
|
|
287
303
|
}
|
|
304
|
+
|
|
305
|
+
/* the archived street: two faint links at the city foot */
|
|
306
|
+
.city-archived { position: absolute; left: 0; right: 0; bottom: 14px; z-index: 2; margin: 0; text-align: center; font-size: 12px; color: var(--ink-faint); opacity: .7; }
|
|
307
|
+
.city-archived a { display: inline-block; min-height: 24px; line-height: 24px; color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--ink-faint) 50%, transparent); }
|
|
308
|
+
.city-archived a:hover { color: var(--ink-soft); }
|
|
309
|
+
|
|
310
|
+
/* the decide view (city-decide.js): one by one, or a table to bulk-answer */
|
|
311
|
+
.decide { position: absolute; inset: 16px; z-index: 9; display: flex; flex-direction: column; gap: 14px; padding: 18px 22px; border-radius: 24px; box-sizing: border-box; overflow: auto; color: var(--ink); }
|
|
312
|
+
.decide[hidden] { display: none; }
|
|
313
|
+
.decide__head { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
|
|
314
|
+
.decide__title { margin: 0; font-size: 22px; font-weight: 400; letter-spacing: -0.02em; }
|
|
315
|
+
.decide__scope { min-height: 32px; padding: 0 10px; border-radius: 10px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-family: var(--font-body); font-size: 13px; }
|
|
316
|
+
.decide__tabs { display: inline-flex; }
|
|
317
|
+
.decide__tabs .kit-tabs { border-bottom: 0; }
|
|
318
|
+
.decide__gap { flex: 1; }
|
|
319
|
+
.decide__counts { font-size: 13px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
320
|
+
.decide__counts b { font-weight: 500; color: var(--ink); }
|
|
321
|
+
.decide__counts b.decide__yours { color: var(--accent); }
|
|
322
|
+
.decide__close { display: inline-flex; align-items: center; min-width: 24px; min-height: 24px; background: none; border: 0; padding: 0; cursor: pointer; opacity: .6; }
|
|
323
|
+
.decide__close kbd { font-size: 10px; }
|
|
324
|
+
.decide__empty, .decide__pos, .decide__said { margin: 0; font-size: 13px; color: var(--ink-soft); text-align: center; }
|
|
325
|
+
.decide__pos { color: var(--ink-faint); }
|
|
326
|
+
.decide__one { display: flex; align-items: center; justify-content: center; gap: 18px; flex: 1; }
|
|
327
|
+
.decide__one .decide-ask { width: min(620px, 100%); box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 24px 28px; border-radius: 24px; background: var(--bg-card); border: 1px solid var(--gov-chip-edge); }
|
|
328
|
+
.decide .decide-ask .ask__q { font-size: 22px; line-height: 1.25; }
|
|
329
|
+
.decide .ask.decide-ask--you { border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent); box-shadow: 0 0 36px color-mix(in srgb, var(--accent) 40%, transparent); }
|
|
330
|
+
.decide__arrow { flex: none; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-size: 22px; cursor: pointer; }
|
|
331
|
+
.decide__arrow[disabled] { opacity: .3; cursor: default; }
|
|
332
|
+
.decide__bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-height: 36px; }
|
|
333
|
+
.decide__bulk-n { font-size: 13px; color: var(--ink-soft); margin-right: 6px; }
|
|
334
|
+
.decide__bulk-btn, .decide__opt { min-height: 28px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-family: var(--font-body); font-size: 12.5px; cursor: pointer; white-space: nowrap; }
|
|
335
|
+
.decide__bulk-btn--rec, .decide__opt--rec { border-color: var(--ink-soft); }
|
|
336
|
+
.decide__bulk-btn:hover, .decide__opt:hover { background: var(--gov-chip-pick); }
|
|
337
|
+
.decide__opt[disabled] { opacity: .45; cursor: not-allowed; }
|
|
338
|
+
.decide__bulk-clear { background: none; border: 0; min-height: 24px; color: var(--ink-soft); font-size: 12.5px; text-decoration: underline; cursor: pointer; }
|
|
339
|
+
.decide__table-wrap { overflow: auto; flex: 1; }
|
|
340
|
+
.decide__table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
341
|
+
.decide__table th { position: sticky; top: 0; text-align: left; font-weight: 500; font-size: 12px; color: var(--ink-soft); padding: 8px 10px; background: var(--bg-card); }
|
|
342
|
+
.decide__table td { padding: 8px 10px; border-top: 1px solid var(--rule-soft); vertical-align: top; }
|
|
343
|
+
.decide__tr--you td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
|
|
344
|
+
.decide__bld { white-space: nowrap; font-weight: 500; }
|
|
345
|
+
.decide__q { min-width: 240px; }
|
|
346
|
+
.decide__age, .decide__table td:nth-child(4) { white-space: nowrap; color: var(--ink-soft); }
|
|
347
|
+
.decide__acts { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
348
|
+
.decide__row-box { width: 18px; height: 18px; margin: 3px; accent-color: var(--ink); }
|
|
349
|
+
.decide__desk { color: var(--ink); font-size: 12.5px; }
|
|
350
|
+
.decide__arrow:focus-visible, .decide__bulk-btn:focus-visible, .decide__opt:focus-visible, .decide__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
351
|
+
@media (max-width: 640px) { .decide { inset: 8px; padding: 14px; } .decide__arrow { display: none; } }
|
|
352
|
+
|
|
353
|
+
/* a typed answer, in the card (city-decide.js drawCard) */
|
|
354
|
+
.ask-field { display: flex; gap: 8px; }
|
|
355
|
+
.ask-field__input { flex: 1; min-width: 0; min-height: 40px; padding: 0 14px; box-sizing: border-box; border-radius: 12px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-family: var(--font-body); font-size: 14px; }
|
|
356
|
+
.ask-field__send { flex: none; min-height: 40px; padding: 0 16px; border-radius: 12px; border: 1px solid var(--gov-chip-edge-pick); background: var(--gov-chip-pick); color: var(--ink); font-family: var(--font-body); font-size: 14px; cursor: pointer; }
|
|
357
|
+
.ask-field__input:focus-visible, .ask-field__send:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
358
|
+
/* a building with more than one item: which one, and the keys that step through them */
|
|
359
|
+
.city-card__step { display: flex; align-items: center; gap: 8px; margin-top: -6px; font-size: 12.5px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
360
|
+
.city-card__stepbtn { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 8px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-size: 13px; cursor: pointer; }
|
|
361
|
+
.city-card__stepbtn:hover { background: var(--gov-chip-pick); }
|
|
362
|
+
.city-card__stepbtn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
363
|
+
.city-card__stepn { min-width: 46px; text-align: center; color: var(--ink); }
|
|
364
|
+
.city-card__hint { margin-left: auto; font-size: 11.5px; color: var(--ink-faint); white-space: pre; }
|
|
365
|
+
.decide__pos-n { font-weight: 500; color: var(--ink); }
|
|
366
|
+
.decide__text { min-height: 28px; min-width: 120px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); color: var(--ink); font-family: var(--font-body); font-size: 12.5px; }
|
|
367
|
+
|
|
368
|
+
/* the beat a decision lands with (city-decide.js flash): a pulse and a word */
|
|
369
|
+
.decide .decide-ask { position: relative; }
|
|
370
|
+
.is-decided { animation: city-decided 900ms cubic-bezier(.2,.7,.3,1); }
|
|
371
|
+
@keyframes city-decided {
|
|
372
|
+
0% { transform: scale(1); }
|
|
373
|
+
25% { transform: scale(.975); box-shadow: 0 0 0 2px var(--ink), 0 0 48px color-mix(in srgb, var(--ink) 30%, transparent); }
|
|
374
|
+
100% { transform: scale(1); }
|
|
375
|
+
}
|
|
376
|
+
.decided-tag { position: absolute; top: 14px; left: 50%; z-index: 3; transform: translateX(-50%); padding: 6px 14px; border-radius: 999px; background: var(--ink); color: var(--bg); font-size: 13px; font-weight: 500; pointer-events: none; animation: city-decided-tag 1100ms ease-out forwards; }
|
|
377
|
+
@keyframes city-decided-tag {
|
|
378
|
+
0% { opacity: 0; transform: translate(-50%, 6px); }
|
|
379
|
+
20% { opacity: 1; transform: translate(-50%, 0); }
|
|
380
|
+
75% { opacity: 1; }
|
|
381
|
+
100% { opacity: 0; transform: translate(-50%, -8px); }
|
|
382
|
+
}
|
|
383
|
+
@media (prefers-reduced-motion: reduce) {
|
|
384
|
+
.is-decided { animation: none; }
|
|
385
|
+
.decided-tag { animation: none; }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Automation as a switchboard (city-switchboard.js): groups of on/off rows */
|
|
389
|
+
.swb { display: flex; flex-direction: column; gap: 14px; }
|
|
390
|
+
.swb__group { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 16px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip); }
|
|
391
|
+
.swb__head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 4px; }
|
|
392
|
+
.swb__title { margin: 0; font-size: 13px; font-weight: 500; letter-spacing: .02em; text-transform: uppercase; color: var(--ink-soft); }
|
|
393
|
+
.swb__sub { font-size: 12px; line-height: 1.4; color: var(--ink-soft); }
|
|
394
|
+
.swb__row { display: flex; align-items: center; gap: 10px; min-height: 40px; border-top: 1px solid var(--rule-soft); padding-top: 6px; }
|
|
395
|
+
.swb__row:first-of-type { border-top: 0; padding-top: 0; }
|
|
396
|
+
.swb__label { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
397
|
+
.swb__name { font-size: 14px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
398
|
+
.swb__fact { font-size: 12px; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
399
|
+
.swb__toggle { flex: none; position: relative; display: inline-flex; align-items: center; width: 64px; height: 30px; padding: 0 8px; box-sizing: border-box; border-radius: 999px; border: 1px solid var(--gov-chip-edge); background: var(--gov-chip-pick); color: var(--ink-soft); font-family: var(--font-body); font-size: 11.5px; cursor: pointer; transition: background 160ms ease; }
|
|
400
|
+
.swb__knob { position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: var(--ink-soft); transition: left 160ms ease, background 160ms ease; }
|
|
401
|
+
.swb__state { margin-left: auto; }
|
|
402
|
+
.swb__row--on .swb__toggle { background: var(--ink); color: var(--bg); justify-content: flex-start; }
|
|
403
|
+
.swb__row--on .swb__knob { left: 37px; background: var(--bg); }
|
|
404
|
+
.swb__row--on .swb__state { margin-left: 0; }
|
|
405
|
+
.swb__toggle[disabled] { cursor: progress; opacity: .6; }
|
|
406
|
+
.swb__toggle:focus-visible, .swb__chip:focus-visible, .swb__star:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
407
|
+
.swb__star { flex: none; min-height: 26px; padding: 0 10px; border-radius: 999px; border: 1px solid var(--gov-chip-edge); background: none; color: var(--ink-soft); font-family: var(--font-body); font-size: 12px; cursor: pointer; }
|
|
408
|
+
.swb__why { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 0 0 4px; }
|
|
409
|
+
.swb__why[hidden] { display: none; }
|
|
410
|
+
.swb__why-ask { font-size: 12px; color: var(--ink-faint); margin-right: 2px; }
|
|
411
|
+
.swb__chip { min-height: 26px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--gov-chip-edge-pick); background: var(--gov-chip-pick); color: var(--ink); font-family: var(--font-body); font-size: 12.5px; cursor: pointer; }
|
|
412
|
+
.swb__note, .swb__none { margin: 0; font-size: 12px; color: var(--ink-faint); }
|
|
413
|
+
.swb__none { font-size: 13.5px; color: var(--ink-soft); }
|
|
414
|
+
@media (prefers-reduced-motion: reduce) { .swb__toggle, .swb__knob { transition: none; } }
|
|
415
|
+
|
|
416
|
+
/* the crab: open this question in Claude to help decide it (city-decide.js) */
|
|
417
|
+
.ask-qline { display: flex; align-items: flex-start; gap: 10px; }
|
|
418
|
+
.ask-qline .ask__q { flex: 1; min-width: 0; }
|
|
419
|
+
.ask-crab { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin-top: 1px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); background: none; color: var(--accent); cursor: pointer; }
|
|
420
|
+
.ask-crab:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
421
|
+
.ask-crab:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
422
|
+
|
|
423
|
+
/* the switchboard's marker over Automation: a small toggle (city-draw.js state 'switch') */
|
|
424
|
+
.city-pin--switch .city-pin__head { width: 34px; height: 20px; background: var(--bg-card); border: 1px solid color-mix(in srgb, var(--ink) 40%, transparent); }
|
|
425
|
+
.city-pin--switch .city-pin__stem { border-left-color: color-mix(in srgb, var(--ink) 40%, transparent); }
|
|
426
|
+
.city-pin__toggle { position: relative; width: 24px; height: 12px; border-radius: 999px; background: color-mix(in srgb, var(--ink-faint) 60%, transparent); }
|
|
427
|
+
.city-pin__toggle-knob { position: absolute; top: 2px; left: 2px; width: 8px; height: 8px; border-radius: 50%; background: var(--ink-soft); }
|
|
428
|
+
.city-pin--on .city-pin__toggle { background: var(--ink); }
|
|
429
|
+
.city-pin--on .city-pin__toggle-knob { left: 14px; background: var(--bg-card); }
|
|
430
|
+
.city-pin--switch { animation: none; }
|
|
431
|
+
|
|
432
|
+
/* a number key pressed once picks that answer; the same key again confirms it */
|
|
433
|
+
.ask__opt.ask__opt--armed { outline: 2px solid var(--focus); outline-offset: 2px; background: var(--gov-chip-pick); }
|
|
434
|
+
.ask__confirm { grid-column: 2 / span 2; font-size: 12px; color: var(--ink); }
|
|
435
|
+
|
|
436
|
+
/* "?": I don't understand this, ask Claude to rewrite it (city-decide.js) */
|
|
437
|
+
.ask-unclear { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin-top: 1px; border-radius: 50%; border: 1px solid var(--gov-chip-edge); background: none; color: var(--ink-soft); font-family: var(--font-body); font-size: 15px; font-weight: 600; cursor: pointer; }
|
|
438
|
+
.ask-unclear:hover { color: var(--ink); background: var(--gov-chip-pick); }
|
|
439
|
+
.ask-unclear--on { background: var(--ink); color: var(--bg); border-color: var(--ink); }
|
|
440
|
+
.ask-unclear:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
441
|
+
|
|
442
|
+
/* the "?" confirm: what a rewrite does, an optional note, then send (city-decide.js) */
|
|
443
|
+
.ask-reword { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 14px; border: 1px solid var(--gov-chip-edge-pick); background: var(--gov-chip-pick); }
|
|
444
|
+
.ask-reword__title { margin: 0; font-size: 14px; font-weight: 500; color: var(--ink); }
|
|
445
|
+
.ask-reword__list { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; line-height: 1.4; color: var(--ink-soft); }
|
|
446
|
+
.ask-reword__note { min-height: 34px; padding: 0 12px; box-sizing: border-box; border-radius: 10px; border: 1px solid var(--gov-chip-edge); background: var(--bg-card); color: var(--ink); font-family: var(--font-body); font-size: 13px; }
|
|
447
|
+
.ask-reword__acts { display: flex; gap: 8px; }
|
|
448
|
+
.ask-reword__go { min-height: 32px; padding: 0 16px; border-radius: 999px; border: 0; background: var(--ink); color: var(--bg); font-family: var(--font-body); font-size: 13px; cursor: pointer; }
|
|
449
|
+
.ask-reword__go[disabled] { opacity: .6; cursor: progress; }
|
|
450
|
+
.ask-reword__no { min-height: 32px; padding: 0 12px; border: 0; background: none; color: var(--ink-soft); font-family: var(--font-body); font-size: 13px; text-decoration: underline; cursor: pointer; }
|
|
451
|
+
.ask-reword__go:focus-visible, .ask-reword__no:focus-visible, .ask-reword__note:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
452
|
+
/* only drawn when something is out for a rewrite; a quiet footnote to the counts */
|
|
453
|
+
.city-card__rewording, .decide__rewording { display: block; margin-top: 1px; font-size: 10.5px; color: var(--ink-faint); text-align: right; }
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
(tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet).
|
|
13
13
|
The prototype carried its own Google Fonts link for the same two faces. -->
|
|
14
14
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
15
|
-
<link rel="stylesheet" href="/builders/city.css?v=2026-10-
|
|
15
|
+
<link rel="stylesheet" href="/builders/city.css?v=2026-10-23-decide11">
|
|
16
16
|
<!-- the ask card in the glass language, shared with the street's deck (task 1004702) -->
|
|
17
17
|
<link rel="stylesheet" href="/builders/street-deck.css?v=2026-10-17-tidy">
|
|
18
18
|
</head>
|
|
@@ -96,9 +96,11 @@
|
|
|
96
96
|
<div class="city-card" id="cityCard" role="dialog" aria-label="A building" hidden></div>
|
|
97
97
|
|
|
98
98
|
<div class="city-door">
|
|
99
|
-
<a class="city-start" id="cityStart" href="
|
|
99
|
+
<a class="city-start" id="cityStart" href="#decide" aria-label="Start governing: everything that waits, one card at a time">start governing</a>
|
|
100
100
|
<h1 class="city-line" id="cityLine" aria-live="polite">reading the docket</h1>
|
|
101
101
|
</div>
|
|
102
|
+
<!-- the street and its buildings are archived: reachable, not on the way -->
|
|
103
|
+
<p class="city-archived">Archived: <a href="/builders/street">Street</a> & <a href="/builders/street#building=charter">Building Level Views</a>.</p>
|
|
102
104
|
</main>
|
|
103
105
|
</div>
|
|
104
106
|
</div>
|
|
@@ -113,11 +115,14 @@
|
|
|
113
115
|
<!-- a building's card answers its first ask in place through the deck's own
|
|
114
116
|
route (task 1004702): the desk rows (street-desk.js over the street's kit)
|
|
115
117
|
and the deck's card and sender (street-deck.js) -->
|
|
118
|
+
<script src="/builders/hall-kit.js?v=2026-10-23-decide11"></script>
|
|
116
119
|
<script src="/builders/street-draw.js?v=2026-10-09-living3"></script>
|
|
117
120
|
<script src="/builders/street-card.js?v=2026-10-04-record1"></script>
|
|
118
121
|
<script src="/builders/street-inside.js?v=2026-10-09-living3"></script>
|
|
119
122
|
<script src="/builders/street-desk.js?v=2026-10-04-record1"></script>
|
|
120
123
|
<script src="/builders/street-deck.js?v=2026-10-13-glass1"></script>
|
|
121
|
-
<script src="/builders/city.js?v=2026-10-
|
|
124
|
+
<script src="/builders/city-decide.js?v=2026-10-23-decide11"></script>
|
|
125
|
+
<script src="/builders/city-switchboard.js?v=2026-10-23-board4"></script>
|
|
126
|
+
<script src="/builders/city.js?v=2026-10-23-decide11"></script>
|
|
122
127
|
</body>
|
|
123
128
|
</html>
|