@bongos/core 1.19.114 → 1.19.115
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 +26 -31
- package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +1 -1
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +1 -1
- package/docs/api/openapi.json +1 -1
- package/modules/provisioning/onboard-plan.js +2 -2
- package/modules/provisioning/routes/provisioning.js +3 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +9 -3
- package/public-landing/projects.html +1382 -38
- package/scripts/gds/audit-authorship.sh +0 -4
- package/scripts/gds/onboard.js +1 -1
- package/src/module-api.js +3 -1
- package/src/platform-server.js +13 -5
- package/tests/cosmos_token_contrast.mjs +10 -7
- package/tests/module-scope-map.mjs +1 -1
- package/tests/onboard.mjs +20 -16
- package/tests/platform_boot.mjs +21 -8
- package/tests/projects_hub.mjs +79 -11
- package/tests/public_landing_projects.mjs +15 -10
- package/public-landing/create.html +0 -1505
package/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
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.115",
|
|
6
|
+
"core_contract": "1.19.115",
|
|
7
|
+
"source_commit": "f98d169e99486bbb55d50e2fb3b18d2d0e035400",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-14T17:50:49.780Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 302,
|
|
13
13
|
"agent_docs_stubbed": 21,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1235,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 1558,
|
|
20
|
+
"tree_sha256": "85dc1b669e706f57dd7ae065edc3c04eba737c5875959566b2487e6b01053e59",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -1172,7 +1172,7 @@
|
|
|
1172
1172
|
{
|
|
1173
1173
|
"path": "docs/adr/0143-onboarding-repo-picker-oauth-scope.md",
|
|
1174
1174
|
"mode": "0000644",
|
|
1175
|
-
"sha256": "
|
|
1175
|
+
"sha256": "6057dfbc25ed45f545f469ee59e7b232fd2b922b1968d1582b519f285f890b7a"
|
|
1176
1176
|
},
|
|
1177
1177
|
{
|
|
1178
1178
|
"path": "docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md",
|
|
@@ -1192,7 +1192,7 @@
|
|
|
1192
1192
|
{
|
|
1193
1193
|
"path": "docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md",
|
|
1194
1194
|
"mode": "0000644",
|
|
1195
|
-
"sha256": "
|
|
1195
|
+
"sha256": "53488f1ff783c49467dd7f9bcf17f5a35c8e3161e2840a89ac5f3f571f7471d9"
|
|
1196
1196
|
},
|
|
1197
1197
|
{
|
|
1198
1198
|
"path": "docs/adr/0146-configurable-reward-mode-cost-plus-only.md",
|
|
@@ -1342,7 +1342,7 @@
|
|
|
1342
1342
|
{
|
|
1343
1343
|
"path": "docs/api/openapi.json",
|
|
1344
1344
|
"mode": "0000644",
|
|
1345
|
-
"sha256": "
|
|
1345
|
+
"sha256": "3b5917da91883faf736528e7ba5600356f06056228a7c81c7d5e025762253699"
|
|
1346
1346
|
},
|
|
1347
1347
|
{
|
|
1348
1348
|
"path": "docs/architecture.md",
|
|
@@ -3837,7 +3837,7 @@
|
|
|
3837
3837
|
{
|
|
3838
3838
|
"path": "modules/provisioning/onboard-plan.js",
|
|
3839
3839
|
"mode": "0000644",
|
|
3840
|
-
"sha256": "
|
|
3840
|
+
"sha256": "e06957844e7161ef42e9971cc1a9b952d9ae87a781b2821d882085ca02c6eccf"
|
|
3841
3841
|
},
|
|
3842
3842
|
{
|
|
3843
3843
|
"path": "modules/provisioning/pollers/liveness-sweep.js",
|
|
@@ -3857,7 +3857,7 @@
|
|
|
3857
3857
|
{
|
|
3858
3858
|
"path": "modules/provisioning/routes/provisioning.js",
|
|
3859
3859
|
"mode": "0000644",
|
|
3860
|
-
"sha256": "
|
|
3860
|
+
"sha256": "1880a5b0812a32feb9dc313024b3a27b1403884316f17fbaad68909872e21535"
|
|
3861
3861
|
},
|
|
3862
3862
|
{
|
|
3863
3863
|
"path": "modules/provisioning/tests/liveness.mjs",
|
|
@@ -4152,12 +4152,12 @@
|
|
|
4152
4152
|
{
|
|
4153
4153
|
"path": "package-lock.json",
|
|
4154
4154
|
"mode": "0000644",
|
|
4155
|
-
"sha256": "
|
|
4155
|
+
"sha256": "d7ad6805c0d040d4d14e0f95b7be3fc175b3e89068e8cb17b08be555827fe029"
|
|
4156
4156
|
},
|
|
4157
4157
|
{
|
|
4158
4158
|
"path": "package.json",
|
|
4159
4159
|
"mode": "0000644",
|
|
4160
|
-
"sha256": "
|
|
4160
|
+
"sha256": "feca9d093739c6fc3c7067bc4fbe725ff7e8cffd9420ddb6d2be632542b03667"
|
|
4161
4161
|
},
|
|
4162
4162
|
{
|
|
4163
4163
|
"path": "public-docs/index.html",
|
|
@@ -4397,18 +4397,13 @@
|
|
|
4397
4397
|
{
|
|
4398
4398
|
"path": "public-landing/assets/cosmos.css",
|
|
4399
4399
|
"mode": "0000644",
|
|
4400
|
-
"sha256": "
|
|
4400
|
+
"sha256": "b615a392fea969c2b0549476843f26d5185cabc6556036e1f3337aacdeac359e"
|
|
4401
4401
|
},
|
|
4402
4402
|
{
|
|
4403
4403
|
"path": "public-landing/buddha.png",
|
|
4404
4404
|
"mode": "0000644",
|
|
4405
4405
|
"sha256": "411319a732791bee09e15b745229b70319488427a492a5edabade5a38461fb4c"
|
|
4406
4406
|
},
|
|
4407
|
-
{
|
|
4408
|
-
"path": "public-landing/create.html",
|
|
4409
|
-
"mode": "0000644",
|
|
4410
|
-
"sha256": "efcc1894c06d1f4755028ae554707a61f8ef6e6753d7d7554f94e3748910f155"
|
|
4411
|
-
},
|
|
4412
4407
|
{
|
|
4413
4408
|
"path": "public-landing/index.html",
|
|
4414
4409
|
"mode": "0000644",
|
|
@@ -4417,7 +4412,7 @@
|
|
|
4417
4412
|
{
|
|
4418
4413
|
"path": "public-landing/projects.html",
|
|
4419
4414
|
"mode": "0000644",
|
|
4420
|
-
"sha256": "
|
|
4415
|
+
"sha256": "961850a566b9fa797036b9ac8b12b3f0eacf5cc6f5fbabbb6230dccd02e836b8"
|
|
4421
4416
|
},
|
|
4422
4417
|
{
|
|
4423
4418
|
"path": "public-landing/world/assets/clouds/cloud-island-large.png",
|
|
@@ -4522,7 +4517,7 @@
|
|
|
4522
4517
|
{
|
|
4523
4518
|
"path": "scripts/gds/audit-authorship.sh",
|
|
4524
4519
|
"mode": "0000644",
|
|
4525
|
-
"sha256": "
|
|
4520
|
+
"sha256": "b574ba3d0e3c279bcd478e0dfdc14eff101ae7675579fa03b536ca086a2e4831"
|
|
4526
4521
|
},
|
|
4527
4522
|
{
|
|
4528
4523
|
"path": "scripts/gds/audit-deps.js",
|
|
@@ -5027,7 +5022,7 @@
|
|
|
5027
5022
|
{
|
|
5028
5023
|
"path": "scripts/gds/onboard.js",
|
|
5029
5024
|
"mode": "0000644",
|
|
5030
|
-
"sha256": "
|
|
5025
|
+
"sha256": "2a8fd60c85b7ef4372a3325d44c9b939f394c5ab1a8364985f2278abfdb8aca4"
|
|
5031
5026
|
},
|
|
5032
5027
|
{
|
|
5033
5028
|
"path": "scripts/gds/onboarding-analyze.js",
|
|
@@ -5732,7 +5727,7 @@
|
|
|
5732
5727
|
{
|
|
5733
5728
|
"path": "src/module-api.js",
|
|
5734
5729
|
"mode": "0000644",
|
|
5735
|
-
"sha256": "
|
|
5730
|
+
"sha256": "e80df1f75bd2a569a72d29eaa00146960390d86ef9a6fd66535d89aac6e6bd39"
|
|
5736
5731
|
},
|
|
5737
5732
|
{
|
|
5738
5733
|
"path": "src/module-loader/catalog.js",
|
|
@@ -5772,7 +5767,7 @@
|
|
|
5772
5767
|
{
|
|
5773
5768
|
"path": "src/platform-server.js",
|
|
5774
5769
|
"mode": "0000644",
|
|
5775
|
-
"sha256": "
|
|
5770
|
+
"sha256": "9567d70acc5150dbdd0f6ea1df996977f2566c8c577bd6c9d0ca05516163dc1b"
|
|
5776
5771
|
},
|
|
5777
5772
|
{
|
|
5778
5773
|
"path": "src/ui/adapters/claude-design/index.js",
|
|
@@ -6237,7 +6232,7 @@
|
|
|
6237
6232
|
{
|
|
6238
6233
|
"path": "tests/cosmos_token_contrast.mjs",
|
|
6239
6234
|
"mode": "0000644",
|
|
6240
|
-
"sha256": "
|
|
6235
|
+
"sha256": "a133a1ed438dfb589b0e31ce2dacced2e38e1047411d85e0086d4c2ff8b88f16"
|
|
6241
6236
|
},
|
|
6242
6237
|
{
|
|
6243
6238
|
"path": "tests/cost.mjs",
|
|
@@ -7032,7 +7027,7 @@
|
|
|
7032
7027
|
{
|
|
7033
7028
|
"path": "tests/module-scope-map.mjs",
|
|
7034
7029
|
"mode": "0000644",
|
|
7035
|
-
"sha256": "
|
|
7030
|
+
"sha256": "e858ff2ae89fbd1577dc00f988c97b71e91f06ee754f5513ba8c18c214d3e181"
|
|
7036
7031
|
},
|
|
7037
7032
|
{
|
|
7038
7033
|
"path": "tests/module_api.mjs",
|
|
@@ -7137,7 +7132,7 @@
|
|
|
7137
7132
|
{
|
|
7138
7133
|
"path": "tests/onboard.mjs",
|
|
7139
7134
|
"mode": "0000644",
|
|
7140
|
-
"sha256": "
|
|
7135
|
+
"sha256": "72590fd2d6f99db3020cb5488ec4f31cef2ad15718a63d8b147ab5adefe347f7"
|
|
7141
7136
|
},
|
|
7142
7137
|
{
|
|
7143
7138
|
"path": "tests/onboarding_gate.mjs",
|
|
@@ -7217,7 +7212,7 @@
|
|
|
7217
7212
|
{
|
|
7218
7213
|
"path": "tests/platform_boot.mjs",
|
|
7219
7214
|
"mode": "0000644",
|
|
7220
|
-
"sha256": "
|
|
7215
|
+
"sha256": "de3bbe68cb648ad5027506f7dcf848e2758e9e67ea65d8c7fb27febbab264845"
|
|
7221
7216
|
},
|
|
7222
7217
|
{
|
|
7223
7218
|
"path": "tests/post_login_landing.mjs",
|
|
@@ -7257,7 +7252,7 @@
|
|
|
7257
7252
|
{
|
|
7258
7253
|
"path": "tests/projects_hub.mjs",
|
|
7259
7254
|
"mode": "0000644",
|
|
7260
|
-
"sha256": "
|
|
7255
|
+
"sha256": "8cd0d3f4ce68085f782fbd3e359039ad6d20198bc706481f165c39ee133cea3a"
|
|
7261
7256
|
},
|
|
7262
7257
|
{
|
|
7263
7258
|
"path": "tests/provision.mjs",
|
|
@@ -7292,7 +7287,7 @@
|
|
|
7292
7287
|
{
|
|
7293
7288
|
"path": "tests/public_landing_projects.mjs",
|
|
7294
7289
|
"mode": "0000644",
|
|
7295
|
-
"sha256": "
|
|
7290
|
+
"sha256": "2d4dea6cd6be287c1d7629009adc64fba526b1ebbe53a800ae43499e1b8e3f18"
|
|
7296
7291
|
},
|
|
7297
7292
|
{
|
|
7298
7293
|
"path": "tests/public_mirror_export.mjs",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
10
|
-
The onboarding wizard at `/create` (
|
|
10
|
+
The onboarding wizard at `/create` (`public-landing/create.html`, absorbed into `projects.html` `?view=new` by task 1002763) had the visitor **type `owner/repo` by hand** (adopt) and, for a fresh project, do a **manual** "New repository on github.com → leave it empty" step. Owner feedback: make it real — let the signed-in user **pick from their own repos** (adopt) and **auto-create the empty repo** (fresh).
|
|
11
11
|
|
|
12
12
|
Blocker: the wizard's GitHub sign-in requests only `read:user` ([auth.js `SCOPE`](../../src/bongos/auth.js)), which cannot list or create repos, and `completeWebFlow` discarded the OAuth token after reading the username. Two ways forward were weighed:
|
|
13
13
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## Context
|
|
9
9
|
|
|
10
|
-
Owner design review of the `/create` wizard (
|
|
10
|
+
Owner design review of the `/create` wizard (`public-landing/create.html`, absorbed into `projects.html` `?view=new` by task 1002763) asked that a new project be reachable at a **free `<handle>.<platform>` address that works out of the box** (sign-in included), with **bring-your-own-domain** as the optional upgrade — i.e. the handle becomes a real subdomain, not just an internal name.
|
|
11
11
|
|
|
12
12
|
Today `/create` always provisions the **`standalone`** shape (the owner's own GitHub repo + a pinned `@bongos/core`, run **control-plane-local** on the hub box), and sign-in on a standalone requires the owner to hand-create their own GitHub OAuth app. The natural-looking implementation was: default the address to `<handle>.cloudbongos.com` and extend the hub federation ([ADR 0141](<redacted>.md)) — which already gives co-tenant instances zero-setup sign-in — to standalone instances on that subdomain. A pre-build security review found this **UNSAFE** on two independent counts.
|
|
13
13
|
|
package/docs/api/openapi.json
CHANGED
|
@@ -8733,7 +8733,7 @@
|
|
|
8733
8733
|
"provisioning"
|
|
8734
8734
|
],
|
|
8735
8735
|
"summary": "GET /provisioning/onboard-plan",
|
|
8736
|
-
"description": "GET /provisioning/onboard-plan?mode=greenfield|adopt&domain=<host> — the CANONICAL onboarding step sequence (task 2085; goal 35 / criterion 165: \"the canonical step sequence is the source of truth; skill/CLI/hall are forms over it\"). The
|
|
8736
|
+
"description": "GET /provisioning/onboard-plan?mode=greenfield|adopt&domain=<host> — the CANONICAL onboarding step sequence (task 2085; goal 35 / criterion 165: \"the canonical step sequence is the source of truth; skill/CLI/hall are forms over it\"). The hub's ?view=new wizard fetches it so its human-steps checklist can't drift from the CLI's (scripts/gds/onboard.js reads the same modules/provisioning/onboard-plan.js). `domain` relabels the terminal enter-hall step with the instance's own hall address (task 1002703); a non-hostname is dropped — clients render these labels, so unvalidated input must never be echoed back. rank: public — the signed-out hub wizard (/projects?view=new) reads it; it is the same public runbook the /new-project skill documents (no write, no secret).\n\n**Rank:** `public` — No authentication — any caller.",
|
|
8737
8737
|
"x-rank": "public",
|
|
8738
8738
|
"x-source": "modules/provisioning/routes/provisioning.js",
|
|
8739
8739
|
"responses": {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Goal 35 / criterion 165 names the sequence as the source of truth: "The canonical
|
|
4
4
|
// step sequence is the source of truth; skill/CLI/hall are forms over it." This file
|
|
5
|
-
// is that ONE source. The CLI (`bongos onboard`, scripts/gds/onboard.js)
|
|
6
|
-
//
|
|
5
|
+
// is that ONE source. The CLI (`bongos onboard`, scripts/gds/onboard.js) and the hub's
|
|
6
|
+
// ?view=new create wizard (task 1002763) read it — via a direct
|
|
7
7
|
// require (the CLI) or the public GET /provisioning/onboard-plan route (the web) — so
|
|
8
8
|
// the sequence can never drift between the forms (task 2085, anti-drift).
|
|
9
9
|
//
|
|
@@ -611,13 +611,13 @@ module.exports = function provisioningRoutes() {
|
|
|
611
611
|
|
|
612
612
|
// GET /provisioning/onboard-plan?mode=greenfield|adopt&domain=<host> — the CANONICAL
|
|
613
613
|
// onboarding step sequence (task 2085; goal 35 / criterion 165: "the canonical step
|
|
614
|
-
// sequence is the source of truth; skill/CLI/hall are forms over it"). The
|
|
615
|
-
//
|
|
614
|
+
// sequence is the source of truth; skill/CLI/hall are forms over it"). The hub's
|
|
615
|
+
// ?view=new wizard fetches it so its human-steps checklist can't drift
|
|
616
616
|
// from the CLI's (scripts/gds/onboard.js reads the same
|
|
617
617
|
// modules/provisioning/onboard-plan.js). `domain` relabels the terminal enter-hall
|
|
618
618
|
// step with the instance's own hall address (task 1002703); a non-hostname is dropped
|
|
619
619
|
// — clients render these labels, so unvalidated input must never be echoed back.
|
|
620
|
-
// rank: public — the signed-out
|
|
620
|
+
// rank: public — the signed-out hub wizard (/projects?view=new) reads it; it is the same public
|
|
621
621
|
// runbook the /new-project skill documents (no write, no secret).
|
|
622
622
|
router.get('/provisioning/onboard-plan', (req, res) => {
|
|
623
623
|
const mode = req.query.mode === 'adopt' ? 'adopt' : 'greenfield';
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.115",
|
|
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.115",
|
|
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.115",
|
|
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",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════════════
|
|
2
2
|
Cloud Bongos — cosmos.css (task 1002696, the R07 redesign)
|
|
3
3
|
The shared token + component layer for the owner-facing project surfaces
|
|
4
|
-
(/
|
|
4
|
+
(/projects — the hub carrying the map, your projects, and the create wizard
|
|
5
|
+
at ?view=new since task 1002763).
|
|
5
6
|
|
|
6
7
|
THE LOOK — ember marigold (owner, 2026-08-13; task 1002748, and before it
|
|
7
8
|
the 2026-08-12 Loop 2 decisions). A LIGHT/DARK mode flips the WHOLE WORLD,
|
|
@@ -51,6 +52,9 @@
|
|
|
51
52
|
/* semantic state tier — each is painted as 12px/700 chip TEXT on its own
|
|
52
53
|
-soft tint, so each must clear 4.5:1 against that tint AND the plain card. */
|
|
53
54
|
--ok:#0e6b31; --warn:#8b4d03; --err:#bb1f1f;
|
|
55
|
+
/* the label INK on an --ok fill (the wizard tick, sdone chips, Copied) --
|
|
56
|
+
dark flips --ok to a bright mint, where white ink drops to 1.74:1 */
|
|
57
|
+
--on-ok:#ffffff;
|
|
54
58
|
|
|
55
59
|
/* chrome tier — the WHOLE WORLD flips with the mode (owner, 2026-08-12,
|
|
56
60
|
Loop 2: light = the sunrise white/orange page, dark = the gate's space).
|
|
@@ -95,6 +99,7 @@
|
|
|
95
99
|
--rule:#5e3521; --rule-soft:#3f2317;
|
|
96
100
|
--accent-deep:color-mix(in srgb, var(--accent) 45%, #ffffff);
|
|
97
101
|
--ok:#4ade80; --warn:#fbbf24; --err:#f87171;
|
|
102
|
+
--on-ok:#0b2e18;
|
|
98
103
|
--page-bg:#150c06;
|
|
99
104
|
--sky-bg:#150c06;
|
|
100
105
|
--star-display:block;
|
|
@@ -120,6 +125,7 @@
|
|
|
120
125
|
--rule:#5e3521; --rule-soft:#3f2317;
|
|
121
126
|
--accent-deep:color-mix(in srgb, var(--accent) 45%, #ffffff);
|
|
122
127
|
--ok:#4ade80; --warn:#fbbf24; --err:#f87171;
|
|
128
|
+
--on-ok:#0b2e18;
|
|
123
129
|
--page-bg:#150c06;
|
|
124
130
|
--sky-bg:#150c06;
|
|
125
131
|
--star-display:block;
|
|
@@ -336,11 +342,11 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
336
342
|
.strip.flowDown .stages li.now .slbl,.strip.flowDown .stages li.done .slbl{color:var(--ink-soft);}
|
|
337
343
|
|
|
338
344
|
/* ── layout primitives (task 1002748, direction §6). cosmos.css was built for
|
|
339
|
-
|
|
345
|
+
the create wizard and /projects — two single-column forms — so it had no page container,
|
|
340
346
|
no type scale below h1, no section rhythm and no grid. The landing page needed
|
|
341
347
|
all five; they live HERE rather than page-locally so the marketing surface and
|
|
342
348
|
the working surfaces stay one system instead of two that merely resemble each
|
|
343
|
-
other. `.hero` above is the /
|
|
349
|
+
other. `.hero` above is the /projects page-title block and is a
|
|
344
350
|
different thing from a landing hero — both are kept. ── */
|
|
345
351
|
.wrap{position:relative;z-index:1;max-width:1060px;margin:0 auto;padding:0 clamp(16px,4vw,40px);}
|
|
346
352
|
.sec{margin-bottom:var(--pad-xl);}
|