@bongos/core 1.19.124 → 1.19.126
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 +11 -11
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +20 -36
- package/public-landing/projects.html +17 -7
- package/src/module-api.js +5 -1
- package/tests/cosmos_token_contrast.mjs +140 -8
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.126",
|
|
6
|
+
"core_contract": "1.19.126",
|
|
7
|
+
"source_commit": "b56cedc2da8ef6691bd7990c6e3219896694e540",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-15T00:16:09.571Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 303,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 1569,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "5703791569f4c26556ad21f0bbcf605faf1b42cfd3631a1ce5f25a05269fd4b4",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -4167,12 +4167,12 @@
|
|
|
4167
4167
|
{
|
|
4168
4168
|
"path": "package-lock.json",
|
|
4169
4169
|
"mode": "0000644",
|
|
4170
|
-
"sha256": "
|
|
4170
|
+
"sha256": "64edc372bb49cd5c30eb5a1d46f54361293de787d1717d2e116f52568ff93f2c"
|
|
4171
4171
|
},
|
|
4172
4172
|
{
|
|
4173
4173
|
"path": "package.json",
|
|
4174
4174
|
"mode": "0000644",
|
|
4175
|
-
"sha256": "
|
|
4175
|
+
"sha256": "c652ffaf3901e4ccc8f64ff9340f7f4f6c418ab738fc52f2b71450083d2a4e97"
|
|
4176
4176
|
},
|
|
4177
4177
|
{
|
|
4178
4178
|
"path": "public-docs/index.html",
|
|
@@ -4412,7 +4412,7 @@
|
|
|
4412
4412
|
{
|
|
4413
4413
|
"path": "public-landing/assets/cosmos.css",
|
|
4414
4414
|
"mode": "0000644",
|
|
4415
|
-
"sha256": "
|
|
4415
|
+
"sha256": "a55b4dd516485060edb4f1cd0be5164bd2026d77186d9b19c1f728a64eda9c7b"
|
|
4416
4416
|
},
|
|
4417
4417
|
{
|
|
4418
4418
|
"path": "public-landing/buddha.png",
|
|
@@ -4427,7 +4427,7 @@
|
|
|
4427
4427
|
{
|
|
4428
4428
|
"path": "public-landing/projects.html",
|
|
4429
4429
|
"mode": "0000644",
|
|
4430
|
-
"sha256": "
|
|
4430
|
+
"sha256": "6dcb73054fa58d3b0254f1d82a7f639ed465db2c2fd1e83e26f29b80532047e5"
|
|
4431
4431
|
},
|
|
4432
4432
|
{
|
|
4433
4433
|
"path": "public-landing/world/assets/clouds/cloud-island-large.png",
|
|
@@ -5757,7 +5757,7 @@
|
|
|
5757
5757
|
{
|
|
5758
5758
|
"path": "src/module-api.js",
|
|
5759
5759
|
"mode": "0000644",
|
|
5760
|
-
"sha256": "
|
|
5760
|
+
"sha256": "c64972eb393e195b4f24de3459036423077430a5cf643fd2e3a8da525ab3af56"
|
|
5761
5761
|
},
|
|
5762
5762
|
{
|
|
5763
5763
|
"path": "src/module-loader/catalog.js",
|
|
@@ -6267,7 +6267,7 @@
|
|
|
6267
6267
|
{
|
|
6268
6268
|
"path": "tests/cosmos_token_contrast.mjs",
|
|
6269
6269
|
"mode": "0000644",
|
|
6270
|
-
"sha256": "
|
|
6270
|
+
"sha256": "3689ce2b23d0baedb5a277676e939af712cea8d0cb3c07857e33f36eb12e1233"
|
|
6271
6271
|
},
|
|
6272
6272
|
{
|
|
6273
6273
|
"path": "tests/cost.mjs",
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.126",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.126",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.126",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
--ink:#fdeedd; --ink-soft:#dcb693; --ink-faint:#b89272;
|
|
99
99
|
--rule:#5e3521; --rule-soft:#3f2317;
|
|
100
100
|
--accent-deep:color-mix(in srgb, var(--accent) 45%, #ffffff);
|
|
101
|
+
--sea-ink:color-mix(in srgb, var(--sea) 65%, #ffffff);
|
|
101
102
|
--ok:#4ade80; --warn:#fbbf24; --err:#f87171;
|
|
102
103
|
--on-ok:#0b2e18;
|
|
103
104
|
--page-bg:#150c06;
|
|
@@ -124,6 +125,7 @@
|
|
|
124
125
|
--ink:#fdeedd; --ink-soft:#dcb693; --ink-faint:#b89272;
|
|
125
126
|
--rule:#5e3521; --rule-soft:#3f2317;
|
|
126
127
|
--accent-deep:color-mix(in srgb, var(--accent) 45%, #ffffff);
|
|
128
|
+
--sea-ink:color-mix(in srgb, var(--sea) 65%, #ffffff);
|
|
127
129
|
--ok:#4ade80; --warn:#fbbf24; --err:#f87171;
|
|
128
130
|
--on-ok:#0b2e18;
|
|
129
131
|
--page-bg:#150c06;
|
|
@@ -154,6 +156,10 @@
|
|
|
154
156
|
--err-soft:color-mix(in srgb, var(--err) 12%, var(--bg-card));
|
|
155
157
|
--accent-soft:color-mix(in srgb, var(--accent) 15%, var(--bg-card));
|
|
156
158
|
--sea-soft:color-mix(in srgb, var(--sea) 16%, var(--bg-card));
|
|
159
|
+
/* the strip's STATE-carrying marks (done fill, now ring/pulse) — light uses
|
|
160
|
+
--sea as-is; dark derives brighter (the --accent-deep pattern) so a pack's
|
|
161
|
+
light-tuned sea clears WCAG 1.4.11's 3:1 on the near-black card too */
|
|
162
|
+
--sea-ink:var(--sea);
|
|
157
163
|
--neutral-soft:color-mix(in srgb, var(--ink) 8%, var(--bg-card));
|
|
158
164
|
/* ink-derived so the shadow is a WARM brown on the marigold ground instead of
|
|
159
165
|
the cold navy it used to cast. The dark blocks override it with a plain black
|
|
@@ -207,8 +213,6 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
207
213
|
.lede{font-size:15.5px;color:var(--ink-soft);font-weight:500;line-height:1.55;margin-bottom:24px;max-width:62ch;}
|
|
208
214
|
.lede a{color:var(--accent-deep);font-weight:700;text-decoration:none;}
|
|
209
215
|
.lede a:hover{text-decoration:underline;}
|
|
210
|
-
:root[data-mode="dark"] .lede a{color:var(--sun-lit);}
|
|
211
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .lede a{color:var(--sun-lit);}}
|
|
212
216
|
|
|
213
217
|
/* ── buttons ── */
|
|
214
218
|
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;cursor:pointer;font-family:var(--font-display);font-weight:700;font-size:15px;color:#fff;background:var(--accent);border:none;border-radius:999px;padding:11px 22px;text-decoration:none;box-shadow:0 10px 22px -8px color-mix(in srgb,var(--accent) 70%,transparent);transition:transform .15s ease, box-shadow .15s ease, background .15s ease;}
|
|
@@ -217,24 +221,18 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
217
221
|
.btn:disabled{background:color-mix(in srgb,var(--ink) 12%,var(--bg-deep));color:color-mix(in srgb,var(--ink) 40%,var(--bg-deep));box-shadow:none;cursor:not-allowed;transform:none;}
|
|
218
222
|
.btn.ghost{background:transparent;color:var(--ink-soft);box-shadow:none;border:2px solid var(--line);}
|
|
219
223
|
.btn.ghost:hover{border-color:var(--accent);color:var(--accent-deep);}
|
|
220
|
-
:root[data-mode="dark"] .btn.ghost:hover{color:var(--sun-lit);}
|
|
221
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .btn.ghost:hover{color:var(--sun-lit);}}
|
|
222
224
|
.btn.small{font-size:13.5px;padding:8px 16px;}
|
|
223
225
|
.btn.danger{background:transparent;color:var(--err);box-shadow:none;border:2px solid color-mix(in srgb,var(--err) 35%,transparent);}
|
|
224
226
|
.btn.danger:hover{background:var(--err-soft);border-color:var(--err);}
|
|
225
227
|
.btn .gh{width:17px;height:17px;fill:currentColor;}
|
|
226
228
|
.linklike{background:none;border:none;cursor:pointer;font-family:var(--font-body);font-weight:700;font-size:13.5px;color:var(--accent-deep);text-decoration:underline;padding:6px 4px;}
|
|
227
|
-
:root[data-mode="dark"] .linklike{color:var(--sun-lit);}
|
|
228
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .linklike{color:var(--sun-lit);}}
|
|
229
229
|
|
|
230
230
|
/* ── chips: the one status vocabulary (direction §4). Recency rides inside
|
|
231
231
|
(.rec) — "live" always says when it was last verified. ── */
|
|
232
232
|
.chip{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:700;letter-spacing:0.3px;border-radius:999px;padding:4px 12px;background:var(--neutral-soft);color:var(--ink-soft);}
|
|
233
233
|
.chip .cdot{width:7px;height:7px;border-radius:50%;background:var(--ink-faint);flex:0 0 auto;}
|
|
234
|
-
.chip .rec{font-weight:600;
|
|
234
|
+
.chip .rec{font-weight:600;font-size:11.5px;}
|
|
235
235
|
.chip.busy{background:var(--accent-soft);color:var(--accent-deep);}
|
|
236
|
-
:root[data-mode="dark"] .chip.busy{color:var(--sun-lit);}
|
|
237
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .chip.busy{color:var(--sun-lit);}}
|
|
238
236
|
.chip.busy .cdot{background:var(--accent);animation:chipPulse 1.4s ease-in-out infinite;}
|
|
239
237
|
.chip.live{background:var(--ok-soft);color:var(--ok);}
|
|
240
238
|
.chip.live .cdot{background:var(--ok);}
|
|
@@ -272,17 +270,11 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
272
270
|
.projName{font-family:var(--font-display);font-weight:700;font-size:19px;letter-spacing:-0.3px;}
|
|
273
271
|
.projMeta{font-size:13px;font-weight:600;color:var(--ink-faint);margin-top:6px;display:flex;gap:14px;flex-wrap:wrap;}
|
|
274
272
|
.projMeta code{font-family:var(--font-mono);font-size:12.5px;background:var(--bg-deep);border-radius:6px;padding:1px 6px;color:var(--accent-deep);}
|
|
275
|
-
:root[data-mode="dark"] .projMeta code{color:var(--sun-lit);}
|
|
276
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .projMeta code{color:var(--sun-lit);}}
|
|
277
273
|
.addr{margin-top:12px;font-size:14.5px;font-weight:600;color:var(--ink-soft);}
|
|
278
274
|
.addr a{color:var(--accent-deep);font-weight:700;text-decoration:none;font-family:var(--font-mono);font-size:13.5px;}
|
|
279
|
-
:root[data-mode="dark"] .addr a{color:var(--sun-lit);}
|
|
280
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .addr a{color:var(--sun-lit);}}
|
|
281
275
|
.addr a:hover{text-decoration:underline;}
|
|
282
276
|
.addr .none{color:var(--ink-faint);font-style:italic;}
|
|
283
277
|
.addr code{font-family:var(--font-mono);font-size:13px;background:var(--bg-deep);border-radius:6px;padding:1px 7px;color:var(--accent-deep);}
|
|
284
|
-
:root[data-mode="dark"] .addr code{color:var(--sun-lit);}
|
|
285
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .addr code{color:var(--sun-lit);}}
|
|
286
278
|
.attach{display:flex;gap:10px;margin-top:10px;flex-wrap:wrap;}
|
|
287
279
|
.attach input[type=text]{flex:1;min-width:220px;font-family:var(--font-body);font-size:15px;font-weight:600;color:var(--ink);background:var(--bg-card);border:2px solid var(--line);border-radius:12px;padding:9px 14px;outline:none;transition:border-color .15s ease, box-shadow .15s ease;}
|
|
288
280
|
.attach input[type=text]::placeholder{color:var(--ink-faint);font-weight:500;}
|
|
@@ -291,8 +283,6 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
291
283
|
.projMsg.ok{color:var(--ok);}
|
|
292
284
|
.projMsg.err{color:var(--err);}
|
|
293
285
|
.projMsg a{color:var(--accent-deep);font-weight:700;text-decoration:none;}
|
|
294
|
-
:root[data-mode="dark"] .projMsg a{color:var(--sun-lit);}
|
|
295
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .projMsg a{color:var(--sun-lit);}}
|
|
296
286
|
.projMsg a:hover{text-decoration:underline;}
|
|
297
287
|
.projMsg details{margin-top:8px;}
|
|
298
288
|
.projMsg summary{cursor:pointer;font-size:12.5px;font-weight:700;color:var(--ink-faint);}
|
|
@@ -305,8 +295,6 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
305
295
|
the browser's default blue, the one colour in the page that is not ours */
|
|
306
296
|
.finePrint a{color:var(--accent-deep);font-weight:700;text-decoration:none;}
|
|
307
297
|
.finePrint a:hover{text-decoration:underline;}
|
|
308
|
-
:root[data-mode="dark"] .finePrint a{color:var(--sun-lit);}
|
|
309
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .finePrint a{color:var(--sun-lit);}}
|
|
310
298
|
|
|
311
299
|
/* ── progress strips: one visual, per-flow vocabularies (direction §4).
|
|
312
300
|
Default = the sea-blue "working" look; .isLive = verified-landed green;
|
|
@@ -315,13 +303,15 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
315
303
|
.strip .stages{display:flex;list-style:none;margin-bottom:6px;}
|
|
316
304
|
.strip .stages li{flex:1;display:flex;flex-direction:column;align-items:center;gap:7px;position:relative;}
|
|
317
305
|
.strip .stages li:not(:first-child)::before{content:"";position:absolute;top:11px;right:50%;width:100%;height:3px;border-radius:2px;background:var(--sea-soft);z-index:0;margin-right:12px;}
|
|
318
|
-
.strip .stages li.done:not(:first-child)::before{background:var(--sea);}
|
|
306
|
+
.strip .stages li.done:not(:first-child)::before{background:var(--sea-ink);}
|
|
319
307
|
.strip .sdot{position:relative;z-index:1;width:24px;height:24px;border-radius:50%;border:3px solid var(--sea-soft);background:var(--bg-card);display:flex;align-items:center;justify-content:center;}
|
|
320
|
-
.strip .stages li.done .sdot{border-color:var(--sea);background:var(--sea);}
|
|
321
|
-
|
|
322
|
-
.strip .stages li.
|
|
323
|
-
.strip .stages li.now .sdot
|
|
324
|
-
|
|
308
|
+
.strip .stages li.done .sdot{border-color:var(--sea-ink);background:var(--sea-ink);}
|
|
309
|
+
/* tick ink is --on-ok, not #fff — dark's bright fills took a white tick to 1.7:1 */
|
|
310
|
+
.strip .stages li.done .sdot::after{content:"";width:8px;height:5px;border-left:2.5px solid var(--on-ok);border-bottom:2.5px solid var(--on-ok);transform:rotate(-45deg) translate(1px,-1px);}
|
|
311
|
+
.strip .stages li.now .sdot{border-color:var(--sea-ink);}
|
|
312
|
+
.strip .stages li.now .sdot::after{content:"";width:8px;height:8px;border-radius:50%;background:var(--sea-ink);animation:beatPulse 1.2s ease-in-out infinite;}
|
|
313
|
+
/* scale-only: an opacity trough took the pulse below the 3:1 its token clears */
|
|
314
|
+
@keyframes beatPulse{0%,100%{transform:scale(.7)}50%{transform:scale(1.15)}}
|
|
325
315
|
.strip .slbl{font-size:12px;font-weight:700;color:var(--ink-faint);}
|
|
326
316
|
.strip .stages li.now .slbl,.strip .stages li.done .slbl{color:color-mix(in srgb,var(--sea) 40%,var(--ink));}
|
|
327
317
|
.strip .pnote{text-align:center;font-size:13px;font-weight:600;color:var(--ink-soft);min-height:18px;line-height:1.5;}
|
|
@@ -432,8 +422,8 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
432
422
|
/* Home LEAVES the hub, so it never takes the current-view pill and a hairline
|
|
433
423
|
sets it apart. Without it the header offered no way back to the landing page
|
|
434
424
|
except the wordmark, which nothing announced as a link. */
|
|
435
|
-
.navrow .navHome{color:var(--glass-ink);
|
|
436
|
-
.navrow .navHome:hover{
|
|
425
|
+
.navrow .navHome{color:var(--glass-ink);}
|
|
426
|
+
.navrow .navHome:hover{color:var(--chrome-accent);}
|
|
437
427
|
.navSep{width:1px;align-self:stretch;margin:4px 3px;background:var(--glass-border);flex:0 0 auto;}
|
|
438
428
|
/* below the mid breakpoint the three groups stack and centre rather than
|
|
439
429
|
fighting for one row — equal flanks only buy a centred nav while it fits */
|
|
@@ -458,7 +448,9 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
458
448
|
.search svg{width:15px;height:15px;fill:none;stroke:var(--glass-ink);stroke-width:2;flex:0 0 auto;}
|
|
459
449
|
.search input{flex:1;min-width:0;background:none;border:none;outline:none;font-family:var(--font-mono);
|
|
460
450
|
font-size:13px;color:var(--chrome-ink);}
|
|
461
|
-
.
|
|
451
|
+
/* no opacity dim — .75 washed this to 3.87:1, and the .mineBar override
|
|
452
|
+
inherited the multiply so its own token could never fix it (task 1002751) */
|
|
453
|
+
.search input::placeholder{color:var(--glass-ink);}
|
|
462
454
|
.search .count{font-family:var(--font-mono);font-size:11.5px;color:var(--glass-ink);white-space:nowrap;}
|
|
463
455
|
|
|
464
456
|
/* the only-mine filter — a real two-state control, not a link: it filters the
|
|
@@ -525,8 +517,6 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
525
517
|
0 0 0 2px color-mix(in srgb,var(--accent) 55%,transparent);}
|
|
526
518
|
.worldOrb[data-rel="builder"] .badge{background:var(--accent-soft);color:var(--accent-deep);
|
|
527
519
|
border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);}
|
|
528
|
-
:root[data-mode="dark"] .worldOrb[data-rel="builder"] .badge{color:var(--sun-lit);}
|
|
529
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .worldOrb[data-rel="builder"] .badge{color:var(--sun-lit);}}
|
|
530
520
|
.worldOrb .chip{transform:scale(.88);white-space:nowrap;}
|
|
531
521
|
|
|
532
522
|
/* what the only-mine filter shows when you are connected to nothing. Not a
|
|
@@ -570,8 +560,6 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
570
560
|
border:1px solid var(--line);color:var(--ink-faint);white-space:nowrap;}
|
|
571
561
|
.tbl .pill{display:inline-block;font-family:var(--font-mono);font-size:11px;padding:3px 10px;
|
|
572
562
|
border-radius:999px;background:var(--accent-soft);color:var(--accent-deep);}
|
|
573
|
-
:root[data-mode="dark"] .tbl .pill{color:var(--sun-lit);}
|
|
574
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .tbl .pill{color:var(--sun-lit);}}
|
|
575
563
|
.tbl td.right{text-align:right;}
|
|
576
564
|
/* Nothing in an action or status cell may wrap: "Manage →" breaking after the
|
|
577
565
|
space and the chip's recency dropping to a second line both read as a broken
|
|
@@ -627,8 +615,6 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
627
615
|
.projCard .cardTag{font-size:14px;color:var(--ink-faint);font-weight:600;line-height:1.5;margin-bottom:14px;}
|
|
628
616
|
.projCard .cardRel{display:inline-block;font-family:var(--font-mono);font-size:11px;padding:3px 10px;
|
|
629
617
|
border-radius:999px;background:var(--accent-soft);color:var(--accent-deep);margin-bottom:18px;}
|
|
630
|
-
:root[data-mode="dark"] .projCard .cardRel{color:var(--sun-lit);}
|
|
631
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .projCard .cardRel{color:var(--sun-lit);}}
|
|
632
618
|
/* the facts strip (task 1002778): a label/value grid, centered as a block but
|
|
633
619
|
read left-aligned. A hidden pair leaves no gap — the grid row collapses. */
|
|
634
620
|
.projCard .cardMeta{display:grid;grid-template-columns:auto auto;justify-content:center;
|
|
@@ -679,8 +665,6 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
679
665
|
font-size:14px;color:var(--ink-faint);position:relative;z-index:1;}
|
|
680
666
|
.steps li.done .snum{border-color:var(--accent);background:var(--accent);color:#fff;}
|
|
681
667
|
.steps li.now .snum{border-color:var(--accent);color:var(--accent-deep);}
|
|
682
|
-
:root[data-mode="dark"] .steps li.now .snum{color:var(--sun-lit);}
|
|
683
|
-
@media (prefers-color-scheme: dark){:root:not([data-mode="light"]) .steps li.now .snum{color:var(--sun-lit);}}
|
|
684
668
|
.steps .slbl{font-size:12.5px;font-weight:700;color:var(--ink-faint);}
|
|
685
669
|
.steps li.now .slbl,.steps li.done .slbl{color:var(--ink-soft);}
|
|
686
670
|
.createSplit{display:grid;grid-template-columns:1fr 300px;gap:var(--pad-md);align-items:center;}
|
|
@@ -163,7 +163,12 @@ h1[tabindex="-1"]:focus{outline:none;}
|
|
|
163
163
|
step that can't be performed yet (its prerequisite — usually the domain — is missing) */
|
|
164
164
|
.humanSteps>li.sdone{border-color:color-mix(in srgb,var(--ok) 30%,var(--bg-card));background:linear-gradient(180deg,color-mix(in srgb,var(--ok) 8%,var(--bg-card)) 0%,var(--bg-card) 100%);}
|
|
165
165
|
.humanSteps>li.sdone::before{content:"✓";background:var(--ok);color:var(--on-ok);}
|
|
166
|
-
|
|
166
|
+
/* locked = muted TOKENS, not subtree opacity — opacity multiplies after the
|
|
167
|
+
token resolves and took this copy below AA (task 1002751) */
|
|
168
|
+
.humanSteps>li.slocked{border-color:color-mix(in srgb,var(--line) 55%,var(--bg-card));}
|
|
169
|
+
.humanSteps>li.slocked b{color:var(--ink-soft);}
|
|
170
|
+
.humanSteps>li.slocked p{color:var(--ink-faint);}
|
|
171
|
+
.humanSteps>li.slocked::before{color:var(--ink-faint);}
|
|
167
172
|
.humanSteps details{margin-top:10px;}
|
|
168
173
|
.humanSteps summary{cursor:pointer;font-weight:700;font-size:12.5px;color:var(--ink-faint);}
|
|
169
174
|
.humanSteps details p{margin-top:8px;}
|
|
@@ -194,16 +199,19 @@ h1[tabindex="-1"]:focus{outline:none;}
|
|
|
194
199
|
content:"";position:absolute;top:11px;right:50%;width:100%;height:3px;border-radius:2px;
|
|
195
200
|
background:var(--sea-soft);z-index:0;margin-right:12px;
|
|
196
201
|
}
|
|
197
|
-
|
|
202
|
+
/* state marks paint --sea-ink / --on-ok, mirroring cosmos's .strip (task
|
|
203
|
+
1002751) — raw --sea sat at 3.03:1 in dark and the #fff tick at 1.74:1 on
|
|
204
|
+
dark's bright --ok */
|
|
205
|
+
.prog .stages li.done:not(:first-child)::before{background:var(--sea-ink);}
|
|
198
206
|
.prog .sdot{
|
|
199
207
|
position:relative;z-index:1;width:24px;height:24px;border-radius:50%;
|
|
200
208
|
border:3px solid var(--sea-soft);background:var(--bg-card);display:flex;align-items:center;justify-content:center;
|
|
201
209
|
}
|
|
202
|
-
.prog .stages li.done .sdot{border-color:var(--sea);background:var(--sea);}
|
|
203
|
-
.prog .stages li.done .sdot::after{content:"";width:8px;height:5px;border-left:2.5px solid
|
|
204
|
-
.prog .stages li.now .sdot{border-color:var(--sea);}
|
|
210
|
+
.prog .stages li.done .sdot{border-color:var(--sea-ink);background:var(--sea-ink);}
|
|
211
|
+
.prog .stages li.done .sdot::after{content:"";width:8px;height:5px;border-left:2.5px solid var(--on-ok);border-bottom:2.5px solid var(--on-ok);transform:rotate(-45deg) translate(1px,-1px);}
|
|
212
|
+
.prog .stages li.now .sdot{border-color:var(--sea-ink);}
|
|
205
213
|
.prog .stages li.now .sdot::after{
|
|
206
|
-
content:"";width:8px;height:8px;border-radius:50%;background:var(--sea);
|
|
214
|
+
content:"";width:8px;height:8px;border-radius:50%;background:var(--sea-ink);
|
|
207
215
|
animation:beatPulse 1.2s ease-in-out infinite;
|
|
208
216
|
}
|
|
209
217
|
/* idle labels match cosmos's .strip .slbl — the 55% sea mix washed to 4.15:1 in dark */
|
|
@@ -229,7 +237,9 @@ h1[tabindex="-1"]:focus{outline:none;}
|
|
|
229
237
|
|
|
230
238
|
/* the collapsed address step — a confirmation, not a form (task 1002704) */
|
|
231
239
|
.addrConfirm{border:2px solid color-mix(in srgb,var(--ok) 30%,var(--bg-card));border-radius:18px;padding:18px 20px;background:linear-gradient(180deg,color-mix(in srgb,var(--ok) 8%,var(--bg-card)) 0%,var(--bg-card) 100%);margin-bottom:16px;}
|
|
232
|
-
.addrConfirm.optedOut{border-color:var(--line);background:var(--bg);
|
|
240
|
+
.addrConfirm.optedOut{border-color:var(--line);background:var(--bg);}
|
|
241
|
+
.addrConfirm.optedOut .addrBig{color:var(--ink-soft);}
|
|
242
|
+
.addrConfirm.optedOut>p{color:var(--ink-faint);}
|
|
233
243
|
.addrBig{font-family:var(--font-display);font-weight:700;font-size:19px;letter-spacing:-0.3px;line-height:1.4;}
|
|
234
244
|
.addrBig code{font-family:var(--font-mono);font-size:15px;background:var(--bg-deep);border-radius:8px;padding:2px 9px;color:var(--accent-deep);word-break:break-all;}
|
|
235
245
|
.addrConfirm>p{font-size:13.5px;font-weight:500;color:var(--ink-soft);line-height:1.5;margin-top:6px;}
|
package/src/module-api.js
CHANGED
|
@@ -675,8 +675,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
675
675
|
// landed since 1.19.122 with no explicit bump. run 31842559470. (task 1002620)
|
|
676
676
|
// 1.19.124 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
677
677
|
// landed since 1.19.123 with no explicit bump. run 31844281033. (task 1002620)
|
|
678
|
+
// 1.19.125 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
679
|
+
// landed since 1.19.124 with no explicit bump. run 31849445746. (task 1002620)
|
|
680
|
+
// 1.19.126 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
681
|
+
// landed since 1.19.125 with no explicit bump. run 31853055269. (task 1002620)
|
|
678
682
|
// ---------------------------------------------------------------------------
|
|
679
|
-
const CORE_VERSION = '1.19.
|
|
683
|
+
const CORE_VERSION = '1.19.126'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
680
684
|
|
|
681
685
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
682
686
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -143,14 +143,14 @@ const PAIRS = [
|
|
|
143
143
|
['.btn label on its fill', '#ffffff', 'var(--accent)', 4.5],
|
|
144
144
|
['.btn.ghost:hover label', 'var(--accent-deep)', CARD, 4.5],
|
|
145
145
|
['.btn.danger label', 'var(--err)', CARD, 4.5],
|
|
146
|
-
// Inline links
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
146
|
+
// Inline links, code chips, pills, the now-step number: every accent-colored
|
|
147
|
+
// text consumer paints --accent-deep in BOTH modes (task 1002750 deleted the
|
|
148
|
+
// dark --sun-lit recolors — they pinned the locked space palette over the
|
|
149
|
+
// branding pack, so a re-themed instance got Cloud Bongos orange links).
|
|
150
|
+
// The dark blocks derive --accent-deep from the pack-settable --accent.
|
|
150
151
|
['inline link on a card', 'var(--accent-deep)', CARD, 4.5],
|
|
151
152
|
['inline link on the page ground', 'var(--accent-deep)', 'var(--bg)', 4.5],
|
|
152
153
|
['code chip on --bg-deep', 'var(--accent-deep)', 'var(--bg-deep)', 4.5],
|
|
153
|
-
['cosmos.css dark link (--sun-lit)', 'var(--sun-lit)', CARD, 4.5, 'dark'],
|
|
154
154
|
// body copy
|
|
155
155
|
['--ink body copy', 'var(--ink)', CARD, 4.5],
|
|
156
156
|
['--ink-soft secondary copy', 'var(--ink-soft)', CARD, 4.5],
|
|
@@ -162,9 +162,24 @@ const PAIRS = [
|
|
|
162
162
|
['.chip.live label', 'var(--ok)', 'var(--ok-soft)', 4.5],
|
|
163
163
|
['.chip.maybe label', 'var(--warn)', 'var(--warn-soft)', 4.5],
|
|
164
164
|
['.chip.down/.bad label', 'var(--err)', 'var(--err-soft)', 4.5],
|
|
165
|
-
// .chip.busy
|
|
166
|
-
|
|
167
|
-
['.chip.busy label', 'var(--
|
|
165
|
+
// .chip.busy + the .tbl .pill / .cardRel / builder-badge family: accent-deep
|
|
166
|
+
// ink on the accent-soft tint, both modes
|
|
167
|
+
['.chip.busy label', 'var(--accent-deep)', 'var(--accent-soft)', 4.5],
|
|
168
|
+
// lifecycle strip STATE INDICATORS (task 1002751): non-text at the WCAG
|
|
169
|
+
// 1.4.11 bar of 3.0. --sea-ink derives brighter in dark exactly the way
|
|
170
|
+
// --accent-deep does, so a pack's light-tuned sea can't vanish on the dark
|
|
171
|
+
// card; the done tick takes --on-ok (the ink-on-a-filled-state-dot token).
|
|
172
|
+
['strip done/now indicator on card', 'var(--sea-ink)', CARD, 3.0],
|
|
173
|
+
['strip done fill vs its idle rail', 'var(--sea-ink)', 'var(--sea-soft)', 3.0],
|
|
174
|
+
['strip indicator on the strip tint', 'var(--sea-ink)', 'color-mix(in srgb,var(--sea) 8%,var(--bg-card))', 3.0],
|
|
175
|
+
['strip done tick on its fill', 'var(--on-ok)', 'var(--sea-ink)', 3.0],
|
|
176
|
+
['flowDown done tick on its fill', 'var(--on-ok)', 'var(--ink-faint)', 3.0],
|
|
177
|
+
['.steps done/now ring on card', 'var(--accent)', CARD, 3.0],
|
|
178
|
+
['.steps done vs idle connector', 'var(--accent)', 'var(--line)', 3.0],
|
|
179
|
+
// the opted-out address card swaps to the page ground (--bg); its muted copy
|
|
180
|
+
// must still measure (19px/700 headline = large text, 3.0)
|
|
181
|
+
['optedOut .addrBig (large) on --bg', 'var(--ink-soft)', 'var(--bg)', 3.0],
|
|
182
|
+
['addrOpt warning on --bg', 'var(--warn)', 'var(--bg)', 4.5],
|
|
168
183
|
// lifecycle strip: 12px/700
|
|
169
184
|
['.strip .slbl idle', 'var(--ink-faint)', CARD, 4.5],
|
|
170
185
|
['.strip .slbl now/done', 'color-mix(in srgb,var(--sea) 40%,var(--ink))', CARD, 4.5],
|
|
@@ -212,6 +227,123 @@ for (const mode of ['light', 'dark']) {
|
|
|
212
227
|
});
|
|
213
228
|
}
|
|
214
229
|
|
|
230
|
+
// The gate's LOCKED sky palette — deliberately absent from COLOR_VARS, so a
|
|
231
|
+
// branding pack can never re-theme these. Dark GROUNDS are allowed (dark mode IS
|
|
232
|
+
// the gate's space, by design); text painted with one shows Cloud Bongos orange
|
|
233
|
+
// on every re-themed instance, beside its own brand color (task 1002750; same
|
|
234
|
+
// class as the --chrome-accent leak in 1002749).
|
|
235
|
+
const LOCKED = ['sun-lit', 'gold', 'gold-soft', 'nebula', 'space-deep', 'space-mid', 'space-high'];
|
|
236
|
+
const LOCKED_REF = new RegExp(`var\\(\\s*--(?:${LOCKED.join('|')})\\s*[,)]`);
|
|
237
|
+
|
|
238
|
+
test('no rule paints text with the locked space palette', () => {
|
|
239
|
+
// The 2026-08-13 state: thirteen dark-mode pairs pinning links/chips/pills to
|
|
240
|
+
// --sun-lit. Property-anchored (background-color:/border-color: fills with
|
|
241
|
+
// their own fixed ink are fine) and value-wide, so color-mix()/fallback/padded
|
|
242
|
+
// spellings are caught too. Comments are stripped first — quoting the old rule
|
|
243
|
+
// in prose must not fail the build.
|
|
244
|
+
const stripped = src.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
245
|
+
const leaks = [];
|
|
246
|
+
for (const m of stripped.matchAll(/(?:^|[;{\s])(color|fill|stroke)\s*:\s*([^;}]*)/g)) {
|
|
247
|
+
if (LOCKED_REF.test(m[2])) leaks.push(`${m[1]}:${m[2].trim()}`);
|
|
248
|
+
}
|
|
249
|
+
assert.deepEqual(leaks, [], `space-palette tokens used as text color:\n ${leaks.join('\n ')}\n`);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test('dark blocks never re-point a token at the locked space palette', () => {
|
|
253
|
+
// The seam the literal guard can't see: a dark block re-pointing a token the
|
|
254
|
+
// text consumers use (--accent-deep:var(--sun-lit)) paints every link orange
|
|
255
|
+
// while no color: declaration names a locked token — and at (0,2,0) no pack
|
|
256
|
+
// can ever win it back. Dark grounds that want the space look use literals.
|
|
257
|
+
// (The typeCard's 40%-gold-soft heading mix is fine: a per-TYPE tint in the
|
|
258
|
+
// light tier, where the pack still owns every brand token.)
|
|
259
|
+
for (const [where, block] of [
|
|
260
|
+
[':root[data-mode="dark"]', darkExplicit],
|
|
261
|
+
['the prefers-color-scheme twin', darkMedia],
|
|
262
|
+
]) {
|
|
263
|
+
for (const [name, value] of Object.entries(block)) {
|
|
264
|
+
assert.ok(
|
|
265
|
+
!LOCKED_REF.test(value),
|
|
266
|
+
`${where}: ${name}:${value} references a locked space-palette token`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// opacity multiplies AFTER the token resolves, so a dimmed subtree's contrast
|
|
273
|
+
// is invisible to every token assertion above (task 1002751: .slocked at .6
|
|
274
|
+
// took 13.5px copy to 3.02:1; .chip .rec at .72 took recency to 3.48:1;
|
|
275
|
+
// .addrConfirm.optedOut at .75 took its note to 3.43:1; a placeholder rule's
|
|
276
|
+
// .75 survived into an override that set only the color, so no token value
|
|
277
|
+
// could ever fix it). Dim with a muted TOKEN so the result stays measured.
|
|
278
|
+
// Known limits, accepted: @keyframes bodies, animation-fill-mode resting
|
|
279
|
+
// values, and JS-set inline opacity are out of static reach — never make an
|
|
280
|
+
// animation or script the resting presenter of text or a state mark.
|
|
281
|
+
const pageSrc = fs
|
|
282
|
+
.readFileSync(path.join(path.dirname(CSS), '..', 'projects.html'), 'utf8')
|
|
283
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
284
|
+
.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
285
|
+
const cssSrc = src.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
286
|
+
const dimsBelowFull = (body) => {
|
|
287
|
+
const m = body.match(/opacity\s*:\s*([\d.]+%?)/);
|
|
288
|
+
if (!m) return false;
|
|
289
|
+
const v = m[1].endsWith('%') ? parseFloat(m[1]) / 100 : parseFloat(m[1]);
|
|
290
|
+
return v < 1;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
test('text is never dimmed by subtree opacity', () => {
|
|
294
|
+
// Two nets. (1) Anywhere in either sheet: a rule that declares BOTH a color
|
|
295
|
+
// and a sub-1 opacity is dimmed text by construction. (2) The create flow's
|
|
296
|
+
// known text containers may not carry opacity at all — this also catches
|
|
297
|
+
// ancestor dims (.createSplit) that net 1 can't see.
|
|
298
|
+
const offenders = [];
|
|
299
|
+
for (const [where, text] of [['cosmos.css', cssSrc], ['projects.html', pageSrc]]) {
|
|
300
|
+
for (const m of text.matchAll(/([^{}@]+)\{([^{}]*)\}/g)) {
|
|
301
|
+
if (/(?:^|[;{\s])color\s*:/.test(m[2]) && dimsBelowFull(m[2])) {
|
|
302
|
+
offenders.push(`${where}: ${m[1].trim().slice(0, 60)} declares color + opacity<1`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
for (const sel of ['\\.humanSteps', '\\.addrConfirm', '\\.prog\\b', '\\.choice', '\\.review', '\\.createSplit', '\\.chip \\.rec']) {
|
|
307
|
+
for (const text of [cssSrc, pageSrc]) {
|
|
308
|
+
for (const m of text.matchAll(new RegExp(`${sel}[^{}]*\\{([^}]*)\\}`, 'g'))) {
|
|
309
|
+
if (dimsBelowFull(m[1])) offenders.push(`text container dimmed: ${m[0].slice(0, 90)}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
assert.deepEqual(offenders, [], `\n ${offenders.join('\n ')}\n`);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test('the .prog strip mirrors .strip: state marks are --sea-ink, ticks are --on-ok', () => {
|
|
317
|
+
// /create's done panel renders the page-local .prog, NOT cosmos's .strip —
|
|
318
|
+
// a re-point of one and not the other is exactly how the 1.74:1 dark tick
|
|
319
|
+
// shipped the first time. State-mark rules (done fill/connector, now
|
|
320
|
+
// ring/pulse, the tick) must use the derived tokens; raw --sea is only legal
|
|
321
|
+
// as a tint ingredient (color-mix) or the idle -soft rail.
|
|
322
|
+
const progRules = [...pageSrc.matchAll(/\.prog[^{}]*\{([^}]*)\}/g)];
|
|
323
|
+
assert.ok(progRules.length >= 5, 'the .prog rules moved out of projects.html — update this test');
|
|
324
|
+
const bad = [];
|
|
325
|
+
for (const m of progRules) {
|
|
326
|
+
const body = m[1];
|
|
327
|
+
if (/(?:border(?:-\w+)?|background)\s*:\s*var\(\s*--sea\s*\)/.test(body)) {
|
|
328
|
+
bad.push(`raw --sea state mark: ${m[0].slice(0, 80)}`);
|
|
329
|
+
}
|
|
330
|
+
if (/border-(?:left|bottom)\s*:[^;]*#fff\b/i.test(body)) {
|
|
331
|
+
bad.push(`hardcoded #fff tick: ${m[0].slice(0, 80)}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
assert.deepEqual(bad, [], `\n ${bad.join('\n ')}\n`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('the pulse animation never dims its mark', () => {
|
|
338
|
+
// beatPulse drives the now-dot in BOTH .strip and .prog. An opacity trough
|
|
339
|
+
// (the old 0.6) put the pulsing mark below the 3:1 its token clears at rest
|
|
340
|
+
// — the PAIRS row above would assert a color the pixel never sustains.
|
|
341
|
+
const kf = cssSrc.match(/@keyframes beatPulse\{([\s\S]*?)\}\s*\}/) ||
|
|
342
|
+
cssSrc.match(/@keyframes beatPulse\{([^@]*)\}/);
|
|
343
|
+
assert.ok(kf, '@keyframes beatPulse not found in cosmos.css — update this test');
|
|
344
|
+
assert.ok(!/opacity\s*:/.test(kf[1]), 'beatPulse dims the now-mark by opacity again');
|
|
345
|
+
});
|
|
346
|
+
|
|
215
347
|
test('the two dark blocks stay in lockstep', () => {
|
|
216
348
|
// cosmos.css carries dark twice — an explicit data-mode hook and a
|
|
217
349
|
// prefers-color-scheme twin. A change to one and not the other is the
|