@bongos/core 1.19.726 → 1.19.728
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 +177 -492
- package/.devcontainer/Dockerfile +1 -1
- package/.devcontainer/devcontainer.json +2 -2
- package/.devcontainer/healthcheck.sh +1 -1
- package/.devcontainer/init-firewall.sh +1 -1
- package/.devcontainer/post-create.sh +2 -2
- package/.env.local.example +1 -1
- package/Dockerfile +1 -1
- package/docs/copy-inventory.md +1 -1
- package/docs/copy-registry.json +9 -9
- package/docs/module-api-changelog.md +4 -0
- package/docs/recipes/devbox-app-release.md +4 -4
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +5 -5
- package/modules/dev-box/app/scripts/gen-brand.js +1 -1
- package/modules/dev-box/app/src/brand.js +1 -1
- package/modules/dev-box/app/test/unit.mjs +16 -16
- package/modules/dev-box/box-access.js +1 -1
- package/modules/dev-box/routes/box.js +1 -1
- package/modules/discord/discord-approvals.js +1 -1
- package/modules/grading/grader-model.js +1 -1
- package/modules/grading/grader-prompt.js +1 -1
- package/modules/grading/grader-workers/quality.js +1 -1
- package/modules/hall-ui/module.json +1 -1
- package/modules/hall-ui/public/brand-apply.js +1 -1
- package/modules/hall-ui/public/shell.js +1 -1
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/lifecycle/conflict-resolve.js +1 -1
- package/modules/lifecycle/db-analytics.js +1 -1
- package/modules/lifecycle/routes/analytics.js +1 -1
- package/modules/onboarding/approval-broadcast.js +1 -1
- package/modules/onboarding/onboarding.js +1 -1
- package/modules/provisioning/tests/liveness.mjs +1 -1
- package/modules/public-landing/public/index.html +1 -1
- package/modules/public-landing/public/projects-floor.states.json +2 -2
- package/modules/public-landing/public/projects.probes.json +4 -4
- package/modules/public-landing/public/projects.states.json +2 -2
- package/modules/status-ui/module.json +1 -1
- package/modules/status-ui/public/status.js +4 -4
- package/modules/status-ui/public/style.css +1 -1
- package/modules/ui-design/kit/fixtures/cost-summary.json +1 -1
- package/modules/ui-design/kit/fixtures/featured-hub.json +1 -1
- package/modules/ui-design/kit/fixtures/featured.json +1 -1
- package/modules/ui-design/kit/fixtures/leaderboard.json +1 -1
- package/modules/ui-design/kit/fixtures/my-projects.json +1 -1
- package/modules/ui-design/kit/fixtures/progress.json +1 -1
- package/modules/ui-design/kit/fixtures/recent-shipped.json +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/cron/style_guide_audit.sh +1 -1
- package/scripts/discord/lib.js +1 -1
- package/scripts/discord/post.js +1 -1
- package/scripts/gds/audit-authorship.sh +1 -1
- package/scripts/gds/audit-replay.sh +29 -2
- package/scripts/gds/audit-ships.js +1 -1
- package/scripts/gds/backfill-sessions.js +2 -2
- package/scripts/gds/cf-tunnel.js +4 -4
- package/scripts/gds/claude-materialize.js +2 -2
- package/scripts/gds/cli-lib.js +6 -6
- package/scripts/gds/cutover-codemod.js +1 -1
- package/scripts/gds/dev-lib.js +2 -2
- package/scripts/gds/diagnose-achievements.js +2 -2
- package/scripts/gds/fitness-checks-identity.js +6 -4
- package/scripts/gds/gen-diagrams.js +1 -1
- package/scripts/gds/leak-scan-allowlist.js +293 -0
- package/scripts/gds/learning-capture.js +1 -1
- package/scripts/gds/linkify-refs.js +2 -2
- package/scripts/gds/local-preview-lib.js +1 -1
- package/scripts/gds/mirror-lineage-check.js +1 -1
- package/scripts/gds/mirror-redact.js +17 -2
- package/scripts/gds/newcomer-floor.templates.json +1 -1
- package/scripts/gds/package-core.js +18 -1
- package/scripts/gds/paste-token.js +1 -1
- package/scripts/gds/provision-units.js +2 -2
- package/scripts/gds/publish-manifest.js +15 -0
- package/scripts/gds/repo-metrics.js +1 -1
- package/scripts/gds/sandbox-stage.js +1 -1
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +1 -1
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +1 -1
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +1 -1
- package/scripts/gds/seed-bongos-tasks.js +2 -2
- package/scripts/gds/seed-gds-v4-tasks.js +1 -1
- package/scripts/gds/seed-medusa-tasks.js +10 -10
- package/scripts/gds/seed-module-upstreaming.js +1 -1
- package/scripts/gds/seed-productization-tasks.js +6 -6
- package/scripts/gds/seed-provisioning-tasks.js +2 -2
- package/scripts/gds/seed-staging.sh +19 -6
- package/scripts/gds/ship-deploy-target.js +1 -1
- package/scripts/gds/ship-flow.js +1 -1
- package/scripts/gds/smoke-gds.js +1 -1
- package/scripts/status-probe.mjs +2 -2
- package/src/bongos/auth-discord.js +2 -2
- package/src/bongos/live-channel.js +1 -1
- package/src/bongos/pool.js +1 -1
- package/src/bongos/routes/auth.js +11 -11
- package/src/bongos/routes/security.js +1 -1
- package/src/bongos/routes.js +1 -1
- package/src/branding.js +1 -1
- package/src/devbox-downloads.js +1 -1
- package/src/instance-config.js +2 -2
- package/src/module-api.js +1 -1
- package/src/module-loader/provenance.js +2 -2
- package/tests/art_stage.mjs +2 -2
- package/tests/auth_anthropic_identity.mjs +1 -1
- package/tests/auth_duplicate_cookie.mjs +1 -1
- package/tests/auth_error_brand.mjs +1 -1
- package/tests/auth_inactive_builder.mjs +1 -1
- package/tests/backup_cli.mjs +4 -4
- package/tests/bongos_box_connect.mjs +2 -2
- package/tests/bongos_downloads.mjs +2 -2
- package/tests/bongos_login.mjs +5 -5
- package/tests/box_connect_e2e.mjs +2 -2
- package/tests/box_dns_repoint.mjs +10 -10
- package/tests/box_host_keys.mjs +1 -1
- package/tests/box_onboard.mjs +9 -9
- package/tests/box_scope_session.mjs +1 -1
- package/tests/box_terminal_ssrf.mjs +7 -7
- package/tests/boxes.mjs +9 -9
- package/tests/branding.mjs +2 -2
- package/tests/bump_version.mjs +2 -2
- package/tests/cf_tunnel.mjs +40 -40
- package/tests/cli_package.mjs +40 -1
- package/tests/cli_token_reissue.mjs +7 -7
- package/tests/cloud_bongos_pack.mjs +1 -1
- package/tests/currency_label.mjs +8 -8
- package/tests/dev_lib.mjs +4 -4
- package/tests/devbox_dmg_backdrop.mjs +1 -1
- package/tests/devbox_downloads.mjs +2 -2
- package/tests/devbox_icons.mjs +1 -1
- package/tests/discord_approvals.mjs +1 -1
- package/tests/discord_oauth.mjs +2 -2
- package/tests/executed_closure.mjs +6 -1
- package/tests/first_admin_bootstrap.mjs +1 -1
- package/tests/gate_approvals.mjs +5 -5
- package/tests/grade_aggregates_unavailable.mjs +1 -1
- package/tests/hook_user_agents.mjs +2 -2
- package/tests/init.mjs +6 -6
- package/tests/instance_config.mjs +1 -1
- package/tests/instance_manifest.mjs +5 -5
- package/tests/instance_mismatch_guard.mjs +13 -13
- package/tests/leak_scan_allowlist.mjs +94 -0
- package/tests/migrate_root_resolution.mjs +4 -4
- package/tests/mirror_redact.mjs +28 -4
- package/tests/module_catalog.mjs +5 -5
- package/tests/module_submissions.mjs +3 -3
- package/tests/package_core.mjs +1 -1
- package/tests/parallel-load.mjs +6 -6
- package/tests/projects_hub.mjs +2 -2
- package/tests/provision.mjs +50 -50
- package/tests/provisioning_github_app_routes.mjs +1 -1
- package/tests/provisioning_onboard_mode.mjs +2 -2
- package/tests/publish_reconciler.mjs +4 -4
- package/tests/sandbox_stage.mjs +1 -1
- package/tests/scrubber_corpus.mjs +3 -3
- package/tests/search_isolation.mjs +1 -1
- package/tests/session_records.mjs +1 -1
- package/tests/ship_card.mjs +6 -6
- package/tests/ship_ci_deploy.mjs +1 -1
- package/tests/single_host_hall.mjs +9 -9
- package/tests/smoke_preflight.mjs +1 -1
- package/tests/smoke_target.mjs +1 -1
- package/tests/status-probe.mjs +1 -1
- package/tests/status_mirror_sync.mjs +1 -1
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +0 -45
- package/docs/design/mocks/_schemes.css +0 -604
- package/docs/design/mocks/component-sheet.html +0 -428
- package/docs/design/mocks/hall/_tokens.css +0 -370
- package/docs/design/mocks/hall/board/v1.html +0 -846
- package/docs/design/mocks/hall/board/v2.html +0 -858
- package/docs/design/mocks/hall/board/v3.html +0 -884
- package/docs/design/mocks/hall/goals/v1.html +0 -1212
- package/docs/design/mocks/hall/goals/v2.html +0 -1192
- package/docs/design/mocks/hall/goals/v3.html +0 -1205
- package/docs/design/mocks/hall/hall-sheet.html +0 -244
- package/docs/design/mocks/hall/reading/v1.html +0 -1125
- package/docs/design/mocks/hall/reading/v2.html +0 -1177
- package/docs/design/mocks/hall/reading/v3.html +0 -1150
- package/docs/design/mocks/hall/settings/v1.html +0 -1238
- package/docs/design/mocks/hall/settings/v2.html +0 -1235
- package/docs/design/mocks/hall/settings/v3.html +0 -1299
- package/docs/design/mocks/hall/task/v1.html +0 -633
- package/docs/design/mocks/hall/task/v2.html +0 -646
- package/docs/design/mocks/hall/task/v3.html +0 -647
- package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-deepfield-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-dust-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-nebula-half.jpg.json +0 -13
- package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg +0 -0
- package/docs/design/mocks/hub/assets/r3-space-starfield-half.jpg.json +0 -13
- package/docs/design/mocks/hub/hub-sheet.html +0 -192
- package/docs/design/mocks/hub/mine.html +0 -465
- package/docs/design/mocks/hub/picker.html +0 -421
- package/docs/design/mocks/hub/planets.html +0 -356
- package/docs/design/mocks/hub/v1.html +0 -1209
- package/docs/design/mocks/hub/v2.html +0 -1257
- package/docs/design/mocks/hub/v3.html +0 -1496
- package/docs/design/mocks/hub/wizard.html +0 -421
- package/docs/design/mocks/landing/landing-sheet.html +0 -131
- package/docs/design/mocks/landing/v1.html +0 -956
- package/docs/design/mocks/landing/v2.html +0 -708
- package/docs/design/mocks/landing/v3.html +0 -911
- package/docs/design/mocks/landing-page-mock.html +0 -687
- package/docs/design/mocks/landing-palettes.html +0 -103
- package/docs/design/mocks/projects-hub-mock.html +0 -991
- package/docs/design/mocks/projects-hub-variants.html +0 -146
- package/docs/design/mocks/projects-page-mock.html +0 -167
- package/docs/design/mocks/world/blue-hud/_tokens.css +0 -246
- package/docs/design/mocks/world/blue-hud/hall.html +0 -595
- package/docs/design/mocks/world/blue-hud/landing.html +0 -424
- package/docs/design/mocks/world/blue-hud/status.html +0 -410
- package/docs/design/mocks/world/chrome-blobs/_tokens.css +0 -479
- package/docs/design/mocks/world/chrome-blobs/hall.html +0 -553
- package/docs/design/mocks/world/chrome-blobs/landing-b.html +0 -581
- package/docs/design/mocks/world/chrome-blobs/landing.html +0 -328
- package/docs/design/mocks/world/chrome-blobs/status.html +0 -416
- package/docs/design/mocks/world/natgeo-editorial/_tokens.css +0 -377
- package/docs/design/mocks/world/natgeo-editorial/hall.html +0 -649
- package/docs/design/mocks/world/natgeo-editorial/landing-b.html +0 -743
- package/docs/design/mocks/world/natgeo-editorial/landing.html +0 -475
- package/docs/design/mocks/world/natgeo-editorial/status.html +0 -437
- package/docs/design/mocks/world/organic-cards/_tokens.css +0 -462
- package/docs/design/mocks/world/organic-cards/hall.html +0 -625
- package/docs/design/mocks/world/organic-cards/landing-b.html +0 -736
- package/docs/design/mocks/world/organic-cards/landing.html +0 -420
- package/docs/design/mocks/world/organic-cards/status.html +0 -458
- package/docs/design/mocks/world/world-sheet.html +0 -156
|
@@ -1,991 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en" data-ground="b">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>/projects as the hub — map · yours · new (task 1002758)</title>
|
|
7
|
-
|
|
8
|
-
<!-- The mock links the SHIPPING stylesheet by relative path so what you see is
|
|
9
|
-
what the build inherits. Serve over HTTP (python -m http.server 8899) — a
|
|
10
|
-
file:// open still resolves this, but the fonts do not. -->
|
|
11
|
-
<link rel="stylesheet" href="../../../modules/public-landing/public/assets/cosmos.css">
|
|
12
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
13
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
14
|
-
<link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;600;700&family=Quicksand:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
15
|
-
|
|
16
|
-
<script>
|
|
17
|
-
/* Pre-paint mode restore — same contract as projects.html:19-23 (localStorage
|
|
18
|
-
key cb-color-mode, data-mode on <html>). Runs before first paint so the
|
|
19
|
-
page never flashes the wrong ground. */
|
|
20
|
-
(function () {
|
|
21
|
-
try {
|
|
22
|
-
var m = localStorage.getItem('cb-color-mode');
|
|
23
|
-
if (m === 'light' || m === 'dark') document.documentElement.setAttribute('data-mode', m);
|
|
24
|
-
var g = localStorage.getItem('cb-mock-ground');
|
|
25
|
-
if (g) document.documentElement.setAttribute('data-ground', g);
|
|
26
|
-
} catch (e) {}
|
|
27
|
-
})();
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<style>
|
|
31
|
-
/* ══════════════════════════════════════════════════════════════════════════
|
|
32
|
-
PAGE-LOCAL SHEET — task 1002758, the /projects hub mock.
|
|
33
|
-
|
|
34
|
-
C1 compliance: there is NO page-local :root block. injectBrandingGlobal()
|
|
35
|
-
splices the pack's :root at the END of <head> at equal specificity, so a
|
|
36
|
-
:root here would silently outrank it and defeat re-branding. Every custom
|
|
37
|
-
property below is scoped to the component that owns it.
|
|
38
|
-
|
|
39
|
-
★ GRADUATION CANDIDATES — authored here, belong in cosmos.css when built.
|
|
40
|
-
Marked ★ inline and listed in direction §6.
|
|
41
|
-
══════════════════════════════════════════════════════════════════════════ */
|
|
42
|
-
|
|
43
|
-
/* ── ★ .shell / .navrow — the persistent hub header. Fixed by the
|
|
44
|
-
gate-navigation direction §4: a header of the PAGE SHELL, not the orb field,
|
|
45
|
-
present in every view, not signed-in-only, not a corner pill. ── */
|
|
46
|
-
.shell{position:relative;z-index:40;display:flex;align-items:center;justify-content:space-between;
|
|
47
|
-
gap:clamp(10px,2vw,22px);padding:16px clamp(16px,4vw,34px);flex-wrap:wrap;}
|
|
48
|
-
/* The wordmark TYPES, so its width changes every 190ms. As the middle child of a
|
|
49
|
-
space-between row the nav would slide with it — the tabs visibly drift left and
|
|
50
|
-
right while the logo animates. Fixing both flanks to `flex:1 1 0` gives them
|
|
51
|
-
equal computed width regardless of content, which pins the nav dead centre and
|
|
52
|
-
lets the mark change width inside its own box. Build must keep this. */
|
|
53
|
-
.shell .mark{flex:1 1 0;min-width:0;
|
|
54
|
-
font-family:var(--font-display);font-weight:700;font-size:22px;letter-spacing:-0.5px;
|
|
55
|
-
text-transform:lowercase;color:var(--chrome-ink);text-decoration:none;text-shadow:var(--chrome-glow);
|
|
56
|
-
white-space:nowrap;}
|
|
57
|
-
.navrow{flex:0 0 auto;}
|
|
58
|
-
.shell .mark span{color:var(--chrome-accent);}
|
|
59
|
-
.shell .caret{color:var(--chrome-accent);animation:cbBlink 1s step-end infinite;font-weight:400;}
|
|
60
|
-
@keyframes cbBlink{50%{opacity:0;}}
|
|
61
|
-
@media (prefers-reduced-motion:reduce){.shell .caret{animation:none;}}
|
|
62
|
-
|
|
63
|
-
/* ★ .navrow — the three destinations. Same pill vocabulary as .btn-space so the
|
|
64
|
-
nav and the chrome buttons read as one family. */
|
|
65
|
-
.navrow{display:flex;align-items:center;gap:4px;background:var(--glass-bg);border:1.5px solid var(--glass-border);
|
|
66
|
-
border-radius:999px;padding:4px;backdrop-filter:blur(4px);}
|
|
67
|
-
.navrow a{font-family:var(--font-display);font-weight:700;font-size:13.5px;color:var(--glass-ink);
|
|
68
|
-
text-decoration:none;padding:7px 15px;border-radius:999px;white-space:nowrap;text-shadow:var(--chrome-glow);}
|
|
69
|
-
.navrow a:hover{color:var(--chrome-accent);}
|
|
70
|
-
.navrow a[aria-current="page"]{background:var(--accent);color:#fff;text-shadow:none;}
|
|
71
|
-
/* Home leaves the hub, so it never takes the current-view pill and is set apart
|
|
72
|
-
by a hairline. Without it the header offered no way back to the landing page
|
|
73
|
-
except the wordmark, which nothing announced as a link. */
|
|
74
|
-
.navrow .navHome{color:var(--glass-ink);opacity:.9;}
|
|
75
|
-
.navrow .navHome:hover{opacity:1;color:var(--chrome-accent);}
|
|
76
|
-
.navSep{width:1px;align-self:stretch;margin:4px 3px;background:var(--glass-border);flex:0 0 auto;}
|
|
77
|
-
.shell-right{flex:1 1 0;display:flex;align-items:center;justify-content:flex-end;
|
|
78
|
-
gap:clamp(8px,1.6vw,14px);flex-wrap:wrap;}
|
|
79
|
-
/* below the mid breakpoint the three groups stack and centre rather than fighting
|
|
80
|
-
for one row — the equal-flanks trick only buys a centred nav while it fits. */
|
|
81
|
-
@media (max-width:820px){
|
|
82
|
-
.shell{justify-content:center;}
|
|
83
|
-
.shell .mark,.shell-right{flex:0 0 auto;}
|
|
84
|
-
.navrow{order:3;flex-basis:100%;justify-content:center;}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/* ── ★ .toolbar — the per-view control strip. Carries the Sky|Table segmented
|
|
88
|
-
control, search, and the "only mine" filter. Present in BOTH browse views,
|
|
89
|
-
which is the owner's 2026-08-13 call. ── */
|
|
90
|
-
.toolbar{position:relative;z-index:30;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
|
|
91
|
-
padding:0 clamp(16px,4vw,34px) 16px;}
|
|
92
|
-
.seg{display:inline-flex;background:var(--glass-bg);border:1.5px solid var(--glass-border);
|
|
93
|
-
border-radius:999px;padding:4px;gap:4px;backdrop-filter:blur(4px);}
|
|
94
|
-
.seg button{font-family:var(--font-display);font-weight:700;font-size:13px;color:var(--glass-ink);
|
|
95
|
-
background:none;border:none;cursor:pointer;padding:7px 16px;border-radius:999px;text-shadow:var(--chrome-glow);}
|
|
96
|
-
.seg button[aria-pressed="true"]{background:var(--accent);color:#fff;text-shadow:none;}
|
|
97
|
-
|
|
98
|
-
.search{flex:1;min-width:190px;max-width:460px;display:flex;align-items:center;gap:9px;
|
|
99
|
-
background:var(--glass-bg);border:1.5px solid var(--glass-border);border-radius:999px;
|
|
100
|
-
padding:8px 16px;backdrop-filter:blur(4px);}
|
|
101
|
-
.search svg{width:15px;height:15px;fill:none;stroke:var(--glass-ink);stroke-width:2;flex:0 0 auto;}
|
|
102
|
-
.search input{flex:1;min-width:0;background:none;border:none;outline:none;font-family:var(--font-mono);
|
|
103
|
-
font-size:13px;color:var(--chrome-ink);}
|
|
104
|
-
.search input::placeholder{color:var(--glass-ink);opacity:.75;}
|
|
105
|
-
.search .count{font-family:var(--font-mono);font-size:11.5px;color:var(--glass-ink);white-space:nowrap;}
|
|
106
|
-
|
|
107
|
-
/* ★ .switch — the "only mine" filter. A real two-state control, not a link:
|
|
108
|
-
it filters the SAME data in place rather than navigating. */
|
|
109
|
-
.switch{display:inline-flex;align-items:center;gap:9px;cursor:pointer;background:var(--glass-bg);
|
|
110
|
-
border:1.5px solid var(--glass-border);border-radius:999px;padding:7px 15px 7px 11px;
|
|
111
|
-
font-family:var(--font-display);font-weight:700;font-size:13px;color:var(--glass-ink);
|
|
112
|
-
backdrop-filter:blur(4px);text-shadow:var(--chrome-glow);white-space:nowrap;}
|
|
113
|
-
.switch input{position:absolute;opacity:0;pointer-events:none;}
|
|
114
|
-
.switch .track{width:32px;height:18px;border-radius:999px;background:color-mix(in srgb,var(--ink) 22%,transparent);
|
|
115
|
-
position:relative;flex:0 0 auto;transition:background .16s ease;}
|
|
116
|
-
.switch .track::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
|
|
117
|
-
background:#fff;transition:transform .16s ease;box-shadow:0 1px 3px rgba(0,0,0,.3);}
|
|
118
|
-
.switch input:checked + .track{background:var(--accent);}
|
|
119
|
-
.switch input:checked + .track::after{transform:translateX(14px);}
|
|
120
|
-
.switch input:focus-visible + .track{outline:2px solid var(--accent);outline-offset:2px;}
|
|
121
|
-
.switch:has(input:checked){color:var(--chrome-accent);border-color:var(--accent);}
|
|
122
|
-
|
|
123
|
-
/* ══ THE MAP ═══════════════════════════════════════════════════════════════
|
|
124
|
-
Three grounds are mocked so they can be compared as rendered pages rather
|
|
125
|
-
than described. The rail switches them; the rejected two stay in the file
|
|
126
|
-
as the record of what was considered (loop rule: never delete a candidate).
|
|
127
|
-
|
|
128
|
-
A · framed — document page; the sky is a bounded panel inside .wrap
|
|
129
|
-
B · dual — full-bleed; marigold daylight in light, warm-umber space in
|
|
130
|
-
dark. This is what cosmos.css ALREADY encodes: --sky-bg is
|
|
131
|
-
#f9d9a8/#150c06 and --star-display flips none/block (:61-62,
|
|
132
|
-
:99-100). No new decision required.
|
|
133
|
-
C · deep — full-bleed, the gate's locked blue-violet space in BOTH modes
|
|
134
|
-
(--space-deep/mid/high, cosmos.css:47-49, platform-fixed).
|
|
135
|
-
═══════════════════════════════════════════════════════════════════════════ */
|
|
136
|
-
|
|
137
|
-
/* ★ .field — the orb field. Component-scoped custom props (C1). */
|
|
138
|
-
.field{position:relative;--field-h:clamp(340px,52vh,540px);height:var(--field-h);overflow:hidden;
|
|
139
|
-
--grid-ink:color-mix(in srgb,var(--rule) 92%,transparent);
|
|
140
|
-
--field-bg:var(--sky-bg);
|
|
141
|
-
--star-vis:var(--star-display);}
|
|
142
|
-
|
|
143
|
-
/* A · framed: the field is a card-like panel that sits in the document */
|
|
144
|
-
html[data-ground="a"] .field{border-radius:26px;box-shadow:var(--shadow-card);
|
|
145
|
-
border:2px solid var(--line);margin-bottom:var(--pad-md);
|
|
146
|
-
--field-bg:var(--space-mid);--grid-ink:rgba(180,200,255,.13);--star-vis:block;}
|
|
147
|
-
html[data-ground="a"] .fieldWrap{padding:0 clamp(16px,4vw,40px);max-width:1060px;margin:0 auto;}
|
|
148
|
-
|
|
149
|
-
/* B · dual-mode full-bleed: the field IS the page ground */
|
|
150
|
-
html[data-ground="b"] .field{--field-h:calc(100vh - 232px);border-radius:0;}
|
|
151
|
-
html[data-ground="b"] .fieldWrap{padding:0;max-width:none;}
|
|
152
|
-
|
|
153
|
-
/* C · locked deep space in both modes */
|
|
154
|
-
html[data-ground="c"] .field{--field-h:calc(100vh - 232px);border-radius:0;
|
|
155
|
-
--field-bg:var(--space-mid);--grid-ink:rgba(180,200,255,.13);--star-vis:block;}
|
|
156
|
-
html[data-ground="c"] .fieldWrap{padding:0;max-width:none;}
|
|
157
|
-
|
|
158
|
-
.field .ground{position:absolute;inset:0;background:var(--field-bg);}
|
|
159
|
-
/* the gravity sheet — a warped grid in the gate, a flat one here: the mock
|
|
160
|
-
settles WHERE things sit, not HOW the sky moves (that is goal 1000031). */
|
|
161
|
-
.field .ground::after{content:"";position:absolute;inset:-10%;
|
|
162
|
-
background-image:linear-gradient(var(--grid-ink) 1px,transparent 1px),
|
|
163
|
-
linear-gradient(90deg,var(--grid-ink) 1px,transparent 1px);
|
|
164
|
-
background-size:74px 74px;
|
|
165
|
-
-webkit-mask-image:radial-gradient(ellipse 62% 58% at 50% 50%,#000 12%,transparent 78%);
|
|
166
|
-
mask-image:radial-gradient(ellipse 62% 58% at 50% 50%,#000 12%,transparent 78%);}
|
|
167
|
-
.field .stars{position:absolute;inset:0;display:var(--star-vis);}
|
|
168
|
-
.field .stars i{position:absolute;width:2px;height:2px;border-radius:50%;background:#fff;opacity:.55;}
|
|
169
|
-
|
|
170
|
-
/* ★ .worldOrb — a project in the field. Colour comes from tokens, never a
|
|
171
|
-
literal: direction §6 records that the five hardcoded ORB_ACCENTS hexes in
|
|
172
|
-
projects.html:221-231 become token derivations so they follow a re-theme. */
|
|
173
|
-
.worldOrb{position:absolute;transform:translate(-50%,-50%);display:flex;flex-direction:column;
|
|
174
|
-
align-items:center;gap:9px;cursor:pointer;background:none;border:none;padding:0;}
|
|
175
|
-
.worldOrb .disc{width:var(--d,96px);height:var(--d,96px);border-radius:50%;position:relative;
|
|
176
|
-
background:radial-gradient(circle at 34% 28%,color-mix(in srgb,var(--acc) 22%,#fff) 0%,
|
|
177
|
-
var(--acc) 42%,color-mix(in srgb,var(--acc) 72%,#000) 100%);
|
|
178
|
-
box-shadow:0 0 34px -4px color-mix(in srgb,var(--acc) 55%,transparent);}
|
|
179
|
-
.worldOrb .disc::after{content:"";position:absolute;inset:0;border-radius:50%;
|
|
180
|
-
border:1.5px solid color-mix(in srgb,#fff 55%,transparent);}
|
|
181
|
-
.worldOrb .nm{font-family:var(--font-display);font-weight:700;font-size:14.5px;color:var(--chrome-ink);
|
|
182
|
-
text-shadow:var(--chrome-glow);white-space:nowrap;}
|
|
183
|
-
.worldOrb .sub{font-family:var(--font-mono);font-size:11.5px;color:var(--chrome-accent);
|
|
184
|
-
text-shadow:var(--chrome-glow);white-space:nowrap;}
|
|
185
|
-
/* on a light ground the orb labels need the page ink, not the chrome ink */
|
|
186
|
-
html[data-ground="a"] .worldOrb .nm,html[data-ground="c"] .worldOrb .nm{color:#fdeedd;text-shadow:0 2px 12px rgba(0,0,0,.65);}
|
|
187
|
-
html[data-ground="a"] .worldOrb .sub,html[data-ground="c"] .worldOrb .sub{color:var(--gold-soft);text-shadow:0 2px 12px rgba(0,0,0,.65);}
|
|
188
|
-
|
|
189
|
-
/* ★ the relationship marks. "Mine" is NOT one thing: GET /my-projects already
|
|
190
|
-
returns { owned, building } off platform_identity_project_memberships, whose
|
|
191
|
-
role is owner|builder|visitor. So the map marks them differently — a solid
|
|
192
|
-
accent ring for owned, a dashed one for building — and the filter keeps both.
|
|
193
|
-
This is the criterion's load-bearing bit: an owner's project is identifiable
|
|
194
|
-
ON the map, and it must not claim ownership the membership row does not say. */
|
|
195
|
-
/* z-index 3: the disc's ::after rim is positioned and later in DOM order, so
|
|
196
|
-
without this the badge is painted over by the orb it labels. */
|
|
197
|
-
.worldOrb .badge{position:absolute;top:-11px;left:50%;transform:translateX(-50%);z-index:3;
|
|
198
|
-
font-family:var(--font-mono);font-size:10.5px;font-weight:500;padding:2px 9px;border-radius:999px;
|
|
199
|
-
white-space:nowrap;background:var(--gold-soft);color:#2b170e;
|
|
200
|
-
box-shadow:0 2px 8px color-mix(in srgb,var(--ink) 30%,transparent);}
|
|
201
|
-
/* the owned ring is ONE ring, not two — a second cream halo read as a defect */
|
|
202
|
-
.worldOrb[data-rel="owner"] .disc{box-shadow:0 0 34px -4px color-mix(in srgb,var(--acc) 55%,transparent),
|
|
203
|
-
0 0 0 3px var(--accent);}
|
|
204
|
-
.worldOrb[data-rel="owner"] .badge{background:var(--accent);color:#fff;}
|
|
205
|
-
/* building, not owning — a lighter claim, said differently on purpose */
|
|
206
|
-
.worldOrb[data-rel="builder"] .disc{box-shadow:0 0 34px -4px color-mix(in srgb,var(--acc) 55%,transparent),
|
|
207
|
-
0 0 0 2px color-mix(in srgb,var(--accent) 55%,transparent);}
|
|
208
|
-
.worldOrb[data-rel="builder"] .badge{background:var(--accent-soft);color:var(--accent-deep);
|
|
209
|
-
border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);}
|
|
210
|
-
/* the verification chip rides the orb — same vocabulary as the list, which is
|
|
211
|
-
the "never alive on the map and unreachable in the list" rule made visible */
|
|
212
|
-
.worldOrb .chip{transform:scale(.88);}
|
|
213
|
-
|
|
214
|
-
/* ★ .fieldEmpty — what "only mine" shows when you are connected to nothing.
|
|
215
|
-
This is not a hypothetical: GET /my-projects returns { owned: [], building: [] }
|
|
216
|
-
for the platform's own archon today, so it is the DAY-ONE state of the filter
|
|
217
|
-
and has to be designed, not discovered. */
|
|
218
|
-
.fieldEmpty{position:absolute;inset:0;display:none;flex-direction:column;align-items:center;
|
|
219
|
-
justify-content:center;gap:14px;text-align:center;padding:26px;z-index:4;}
|
|
220
|
-
.field.isEmpty .fieldEmpty{display:flex;}
|
|
221
|
-
.fieldEmpty p{font-size:15px;font-weight:600;color:var(--chrome-ink);max-width:44ch;line-height:1.55;
|
|
222
|
-
text-shadow:var(--chrome-glow);}
|
|
223
|
-
.fieldEmpty .sub{font-size:13.5px;font-weight:600;color:var(--glass-ink);}
|
|
224
|
-
html[data-ground="a"] .fieldEmpty p,html[data-ground="c"] .fieldEmpty p{color:#fdeedd;text-shadow:0 2px 12px rgba(0,0,0,.65);}
|
|
225
|
-
|
|
226
|
-
.hintbar{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);display:flex;gap:8px;
|
|
227
|
-
flex-wrap:wrap;justify-content:center;font-family:var(--font-mono);font-size:11.5px;
|
|
228
|
-
color:var(--glass-ink);background:var(--glass-bg);border:1.5px solid var(--glass-border);
|
|
229
|
-
border-radius:999px;padding:7px 16px;backdrop-filter:blur(4px);max-width:92%;}
|
|
230
|
-
.hintbar kbd{font-family:var(--font-mono);background:color-mix(in srgb,var(--accent) 24%,transparent);
|
|
231
|
-
border-radius:5px;padding:1px 6px;font-size:11px;color:var(--chrome-accent);}
|
|
232
|
-
html[data-ground="a"] .hintbar,html[data-ground="c"] .hintbar{color:#dcb693;background:rgba(255,255,255,.07);}
|
|
233
|
-
|
|
234
|
-
/* ── ★ .tbl — the table view. Same data, same filter, and the nav is present:
|
|
235
|
-
the gate's table dropped the projects door entirely (verified live). ── */
|
|
236
|
-
.tbl{width:100%;border-collapse:collapse;background:var(--card);border-radius:20px;overflow:hidden;
|
|
237
|
-
box-shadow:var(--shadow-card);}
|
|
238
|
-
.tbl th{text-align:left;font-family:var(--font-display);font-size:11.5px;font-weight:700;
|
|
239
|
-
letter-spacing:.9px;text-transform:uppercase;color:var(--ink-faint);padding:15px 18px;
|
|
240
|
-
border-bottom:2px solid var(--line);cursor:pointer;white-space:nowrap;}
|
|
241
|
-
.tbl th[aria-sort]{color:var(--accent-deep);}
|
|
242
|
-
.tbl td{padding:15px 18px;border-bottom:1px solid var(--line);font-size:14px;font-weight:600;
|
|
243
|
-
color:var(--ink-soft);vertical-align:middle;}
|
|
244
|
-
.tbl tr:last-child td{border-bottom:none;}
|
|
245
|
-
.tbl tr:hover td{background:color-mix(in srgb,var(--accent) 5%,transparent);}
|
|
246
|
-
.tbl .pname{display:flex;align-items:center;gap:11px;}
|
|
247
|
-
.tbl .pdot{width:11px;height:11px;border-radius:50%;background:var(--acc);flex:0 0 auto;
|
|
248
|
-
box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 22%,transparent);}
|
|
249
|
-
.tbl .ptitle{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--ink);}
|
|
250
|
-
.tbl .ptag{font-size:12.5px;color:var(--ink-faint);font-weight:600;}
|
|
251
|
-
.tbl .num{font-family:var(--font-mono);font-weight:500;}
|
|
252
|
-
.tbl .pill{display:inline-block;font-family:var(--font-mono);font-size:11px;padding:3px 10px;
|
|
253
|
-
border-radius:999px;background:var(--accent-soft);color:var(--accent-deep);}
|
|
254
|
-
.tbl .tags{display:flex;gap:6px;flex-wrap:wrap;}
|
|
255
|
-
.tbl .tags span{font-family:var(--font-mono);font-size:10.5px;padding:2px 8px;border-radius:999px;
|
|
256
|
-
border:1px solid var(--line);color:var(--ink-faint);}
|
|
257
|
-
.tbl td.right{text-align:right;}
|
|
258
|
-
/* Nothing in an action or status cell may wrap: "Manage →" breaking after the
|
|
259
|
-
space and the chip's recency dropping to a second line both read as a broken
|
|
260
|
-
control rather than a tight column. The two cells claim their width instead. */
|
|
261
|
-
.tbl .btn,.tbl .chip{white-space:nowrap;}
|
|
262
|
-
.tbl .colStatus{width:1%;white-space:nowrap;}
|
|
263
|
-
.tbl .colGo{width:1%;white-space:nowrap;padding-left:8px;}
|
|
264
|
-
/* the name cell is the one that should absorb the slack */
|
|
265
|
-
.tbl .colName{width:auto;}
|
|
266
|
-
@media (max-width:780px){.tbl .colTags,.tbl .colType{display:none;}}
|
|
267
|
-
|
|
268
|
-
/* ── the create view: a 4-step rail + the bongo pair. The buddha is dropped
|
|
269
|
-
(owner, 2026-08-13) so one mark carries every surface. ── */
|
|
270
|
-
.steps{display:flex;align-items:flex-start;margin-bottom:26px;}
|
|
271
|
-
.steps li{flex:1;display:flex;flex-direction:column;align-items:center;gap:8px;position:relative;list-style:none;}
|
|
272
|
-
.steps li:not(:first-child)::before{content:"";position:absolute;top:15px;right:50%;width:100%;height:3px;
|
|
273
|
-
background:var(--line);margin-right:15px;border-radius:2px;}
|
|
274
|
-
.steps li.done:not(:first-child)::before{background:var(--accent);}
|
|
275
|
-
.steps .snum{width:32px;height:32px;border-radius:50%;border:3px solid var(--line);background:var(--bg-card);
|
|
276
|
-
display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-weight:700;
|
|
277
|
-
font-size:14px;color:var(--ink-faint);position:relative;z-index:1;}
|
|
278
|
-
.steps li.done .snum{border-color:var(--accent);background:var(--accent);color:#fff;}
|
|
279
|
-
.steps li.now .snum{border-color:var(--accent);color:var(--accent-deep);}
|
|
280
|
-
.steps .slbl{font-size:12.5px;font-weight:700;color:var(--ink-faint);}
|
|
281
|
-
.steps li.now .slbl,.steps li.done .slbl{color:var(--ink-soft);}
|
|
282
|
-
|
|
283
|
-
.createSplit{display:grid;grid-template-columns:1fr 300px;gap:var(--pad-md);align-items:center;}
|
|
284
|
-
@media (max-width:840px){.createSplit{grid-template-columns:1fr;}.createSplit .bongoCell{display:none;}}
|
|
285
|
-
/* the hero mark, reused from public-landing/index.html:250-323 at a calmer size.
|
|
286
|
-
Component-scoped skin tokens — the drum head is SKIN, never --bg-card, or it
|
|
287
|
-
turns black in dark mode (landing direction §2 gotcha). */
|
|
288
|
-
.bongos{display:block;width:100%;height:auto;overflow:visible;
|
|
289
|
-
--skin-hi:#fffdf7;--skin-mid:#f4e6cd;--skin-lo:#cdb896;
|
|
290
|
-
/* --drum-shadow carries the fix for task 1002759: the shipped page fills this
|
|
291
|
-
ellipse with var(--ink), which is near-white in dark and paints a glowing
|
|
292
|
-
puddle under the drums instead of a shadow. Same move cosmos.css already
|
|
293
|
-
makes for --shadow-card (:151-153) — ink in light, plain black in dark. */
|
|
294
|
-
--drum-shadow:var(--ink);}
|
|
295
|
-
:root[data-mode="dark"] .bongos{--skin-hi:#fdf7ea;--skin-mid:#efe1c8;--skin-lo:#c3ae90;--drum-shadow:#000;}
|
|
296
|
-
@media (prefers-color-scheme:dark){:root:not([data-mode="light"]) .bongos{--skin-hi:#fdf7ea;--skin-mid:#efe1c8;--skin-lo:#c3ae90;--drum-shadow:#000;}}
|
|
297
|
-
|
|
298
|
-
/* ── ★ .mineBar / .filters — search + state filter for the manage list. Reuses
|
|
299
|
-
.search from the map toolbar; the filter pills carry live counts so a state
|
|
300
|
-
with nothing in it is visible before you click it. ── */
|
|
301
|
-
.mineBar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:20px;}
|
|
302
|
-
.mineBar .search{background:var(--bg-card);border-color:var(--line);}
|
|
303
|
-
.mineBar .search input{color:var(--ink);}
|
|
304
|
-
.mineBar .search input::placeholder{color:var(--ink-faint);}
|
|
305
|
-
.mineBar .search svg{stroke:var(--ink-faint);}
|
|
306
|
-
.mineBar .search .count{color:var(--ink-faint);}
|
|
307
|
-
.filters{display:flex;gap:7px;flex-wrap:wrap;}
|
|
308
|
-
.filters button{display:inline-flex;align-items:center;gap:7px;cursor:pointer;font-family:var(--font-display);
|
|
309
|
-
font-weight:700;font-size:13px;color:var(--ink-soft);background:var(--bg-card);
|
|
310
|
-
border:2px solid var(--line);border-radius:999px;padding:7px 14px;white-space:nowrap;}
|
|
311
|
-
.filters button:hover{border-color:var(--accent);color:var(--accent-deep);}
|
|
312
|
-
.filters button[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:#fff;}
|
|
313
|
-
.filters .n{font-family:var(--font-mono);font-weight:500;font-size:11.5px;opacity:.75;}
|
|
314
|
-
.mineEmpty{font-size:14.5px;font-weight:600;color:var(--ink-soft);padding:10px 0 22px;}
|
|
315
|
-
|
|
316
|
-
/* ── ★ .fieldNote — the honest empty/locked states. A child instance does not
|
|
317
|
-
provision, so it must SAY so rather than fall into the generic alert. ── */
|
|
318
|
-
.fieldNote{border:2px dashed var(--line);border-radius:18px;padding:24px;text-align:center;
|
|
319
|
-
font-size:14.5px;font-weight:600;color:var(--ink-soft);line-height:1.55;}
|
|
320
|
-
|
|
321
|
-
/* ══ MOCK CHROME — not part of the design. ?rail=0 removes all of it. ══ */
|
|
322
|
-
.mockNote{position:relative;z-index:50;max-width:1060px;margin:0 auto 22px;background:var(--bg-card);
|
|
323
|
-
border:2px solid var(--sea);border-left-width:7px;border-radius:16px;padding:16px 20px;
|
|
324
|
-
font-size:13.5px;line-height:1.6;color:var(--ink-soft);}
|
|
325
|
-
.mockNote h4{font-family:var(--font-display);font-size:14.5px;color:var(--sea);margin-bottom:5px;}
|
|
326
|
-
.mockNote b{color:var(--ink);}
|
|
327
|
-
.mockNote kbd{font-family:var(--font-mono);font-size:11.5px;background:var(--neutral-soft);
|
|
328
|
-
border-radius:5px;padding:1px 6px;}
|
|
329
|
-
.rail{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:90;display:flex;
|
|
330
|
-
align-items:center;gap:8px;flex-wrap:wrap;justify-content:center;background:var(--bg-card);
|
|
331
|
-
border:2px solid var(--sea);border-radius:999px;padding:8px 14px;box-shadow:var(--shadow-card);
|
|
332
|
-
max-width:94vw;font-size:12.5px;}
|
|
333
|
-
.rail b{font-family:var(--font-display);font-size:11.5px;letter-spacing:.7px;text-transform:uppercase;
|
|
334
|
-
color:var(--sea);margin-right:2px;}
|
|
335
|
-
.rail button{font-family:var(--font-display);font-weight:700;font-size:12.5px;cursor:pointer;
|
|
336
|
-
border:1.5px solid var(--line);background:var(--bg-card);color:var(--ink-soft);border-radius:999px;padding:5px 12px;}
|
|
337
|
-
.rail button[aria-pressed="true"]{background:var(--sea);border-color:var(--sea);color:#fff;}
|
|
338
|
-
.rail .sep{width:1px;height:18px;background:var(--line);}
|
|
339
|
-
body.rail-off .rail,body.rail-off .mockNote{display:none;}
|
|
340
|
-
[data-apex-only]{outline:none;}
|
|
341
|
-
body.show-apex [data-apex-only]{outline:2px dashed var(--sea);outline-offset:5px;border-radius:8px;position:relative;}
|
|
342
|
-
body.show-apex [data-apex-only]::before{content:"apex-only";position:absolute;top:-11px;left:9px;z-index:5;
|
|
343
|
-
font-family:var(--font-mono);font-size:10px;background:var(--sea);color:#fff;padding:1px 7px;border-radius:999px;}
|
|
344
|
-
body.child-preview [data-apex-only]{display:none !important;}
|
|
345
|
-
.childBanner{display:none;position:sticky;top:0;z-index:60;background:var(--sea);color:#fff;
|
|
346
|
-
text-align:center;font-size:12.5px;font-weight:700;padding:6px;font-family:var(--font-mono);}
|
|
347
|
-
body.child-preview .childBanner{display:block;}
|
|
348
|
-
body.rail-off .childBanner{display:none;}
|
|
349
|
-
</style>
|
|
350
|
-
</head>
|
|
351
|
-
|
|
352
|
-
<body>
|
|
353
|
-
|
|
354
|
-
<div class="childBanner">CHILD-INSTANCE PREVIEW — every apex-only block removed, as stripApexOnly() does on the server</div>
|
|
355
|
-
|
|
356
|
-
<!-- the mode-aware full-page ground. C3: themeMarkup() emits body{background:#f9d9a8}
|
|
357
|
-
after cosmos.css in BOTH modes, so .sky is the only mode-aware page paint. -->
|
|
358
|
-
<div class="sky" aria-hidden="true"></div>
|
|
359
|
-
|
|
360
|
-
<header class="shell">
|
|
361
|
-
<a class="mark" href="/">cloud <span id="typed">bongos</span><span class="caret" aria-hidden="true">▌</span></a>
|
|
362
|
-
|
|
363
|
-
<!-- Home is a PAGE (the landing page at /); the other three are VIEWS of this
|
|
364
|
-
page. They sit in one control because they are all "where can I go from
|
|
365
|
-
here", but the divider keeps the distinction honest. -->
|
|
366
|
-
<nav class="navrow" aria-label="Project hub">
|
|
367
|
-
<a href="/" class="navHome" data-nav="home">Home</a>
|
|
368
|
-
<span class="navSep" aria-hidden="true"></span>
|
|
369
|
-
<a href="?view=map" data-nav="map" aria-current="page">Map</a>
|
|
370
|
-
<a href="?view=mine" data-nav="mine">Your projects</a>
|
|
371
|
-
<a href="?view=new" data-nav="new">New project</a>
|
|
372
|
-
</nav>
|
|
373
|
-
|
|
374
|
-
<div class="shell-right">
|
|
375
|
-
<a class="btn-space" href="/builders" data-apex-only>🏛 Builders' hall</a>
|
|
376
|
-
<button class="mode-toggle" id="mode" title="Light / dark">☾</button>
|
|
377
|
-
<span class="who" id="who">
|
|
378
|
-
<img src="https://avatars.githubusercontent.com/u/64553469?v=4" alt="">jaxri
|
|
379
|
-
</span>
|
|
380
|
-
<a class="btn-space signedOut" id="signin" hidden href="/api/bongos/auth/web/start?return=/projects">Sign in</a>
|
|
381
|
-
</div>
|
|
382
|
-
</header>
|
|
383
|
-
|
|
384
|
-
<div class="mockNote">
|
|
385
|
-
<h4>Mock — task 1002758 · goal 1000061 “Apex UI pass”</h4>
|
|
386
|
-
<b>Fixed, not reopened here:</b> that <code>/projects</code> is the one hub holding map + your projects + create,
|
|
387
|
-
that <code>/create</code> redirects in, and that the entry ritual is gone — all settled by
|
|
388
|
-
<b>front-door-and-hub-direction.md</b> §1–2, whose §7 hands the visual design to this pass.<br>
|
|
389
|
-
<b>Owner calls taken 2026-08-13:</b> the map is what you land on · an <b>only mine</b> filter lives in the map
|
|
390
|
-
<i>and</i> the table · <code>/gate/</code> retires at the apex flip · the buddha is dropped, the bongo pair is the
|
|
391
|
-
mark everywhere.<br>
|
|
392
|
-
<b>Open — this is the one to look at:</b> the hub’s <b>ground</b>. Three are built; switch them on the rail.
|
|
393
|
-
<b>A framed</b> puts the sky in a panel on a document page · <b>B dual-mode</b> is full-bleed and follows
|
|
394
|
-
light/dark (what cosmos.css already encodes) · <b>C deep space</b> stays blue-violet in both modes.<br>
|
|
395
|
-
<kbd>S</kbd> outline apex-only blocks · <kbd>C</kbd> child-instance shape · <kbd>1</kbd><kbd>2</kbd><kbd>3</kbd> views ·
|
|
396
|
-
<kbd>?rail=0</kbd> hides all mock chrome.
|
|
397
|
-
</div>
|
|
398
|
-
|
|
399
|
-
<!-- ══════════════════ VIEW · MAP ══════════════════ -->
|
|
400
|
-
<section id="view-map">
|
|
401
|
-
<div class="toolbar">
|
|
402
|
-
<div class="seg" role="group" aria-label="Map display">
|
|
403
|
-
<button id="sub-sky" aria-pressed="true">Sky</button>
|
|
404
|
-
<button id="sub-table" aria-pressed="false">Table</button>
|
|
405
|
-
</div>
|
|
406
|
-
|
|
407
|
-
<label class="switch" title="Show only projects you own">
|
|
408
|
-
<input type="checkbox" id="onlyMine"><span class="track"></span> Only mine
|
|
409
|
-
</label>
|
|
410
|
-
|
|
411
|
-
<div class="search">
|
|
412
|
-
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
|
|
413
|
-
<input type="text" placeholder="Search projects by name, tag, description…" id="q">
|
|
414
|
-
<span class="count" id="count">4 projects</span>
|
|
415
|
-
</div>
|
|
416
|
-
</div>
|
|
417
|
-
|
|
418
|
-
<!-- ── sky sub-view ── -->
|
|
419
|
-
<div class="fieldWrap" id="sub-sky-body">
|
|
420
|
-
<div class="field">
|
|
421
|
-
<div class="ground"></div>
|
|
422
|
-
<div class="stars" id="stars"></div>
|
|
423
|
-
|
|
424
|
-
<!-- the platform's own orb. apex-only: a child instance has no "this platform".
|
|
425
|
-
data-rel is ILLUSTRATIVE — see the rail's "real memberships" switch. -->
|
|
426
|
-
<button class="worldOrb" style="--acc:var(--accent);--d:122px;left:50%;top:44%"
|
|
427
|
-
data-rel="builder" data-apex-only>
|
|
428
|
-
<span class="badge">you build here</span>
|
|
429
|
-
<span class="disc"></span>
|
|
430
|
-
<span class="nm">Cloud Bongos</span>
|
|
431
|
-
<span class="sub">24 builders</span>
|
|
432
|
-
</button>
|
|
433
|
-
|
|
434
|
-
<button class="worldOrb" style="--acc:var(--sea);--d:74px;left:22%;top:30%" data-rel="owner">
|
|
435
|
-
<span class="badge">yours</span>
|
|
436
|
-
<span class="disc"></span>
|
|
437
|
-
<span class="nm">Off the Boats</span>
|
|
438
|
-
<span class="chip live"><span class="cdot"></span>live <span class="rec">· checked 2m ago</span></span>
|
|
439
|
-
</button>
|
|
440
|
-
|
|
441
|
-
<button class="worldOrb" style="--acc:var(--terracotta);--d:60px;left:78%;top:66%" data-rel="builder">
|
|
442
|
-
<span class="badge">you build here</span>
|
|
443
|
-
<span class="disc"></span>
|
|
444
|
-
<span class="nm">Emersonian Circles</span>
|
|
445
|
-
<span class="chip maybe"><span class="cdot"></span>live? <span class="rec">· last seen 41m ago</span></span>
|
|
446
|
-
</button>
|
|
447
|
-
|
|
448
|
-
<button class="worldOrb" style="--acc:var(--gold-soft);--d:56px;left:33%;top:74%" data-rel="none">
|
|
449
|
-
<span class="disc"></span>
|
|
450
|
-
<span class="nm">Demo</span>
|
|
451
|
-
<span class="sub">live</span>
|
|
452
|
-
</button>
|
|
453
|
-
|
|
454
|
-
<div class="fieldEmpty">
|
|
455
|
-
<p id="emptyMsg">You don’t own or build on anything here yet.</p>
|
|
456
|
-
<span class="sub">Turn the filter off to see what everyone else is building — or start your own.</span>
|
|
457
|
-
<a class="btn small" href="?view=new">Start a project</a>
|
|
458
|
-
</div>
|
|
459
|
-
|
|
460
|
-
<div class="hintbar">
|
|
461
|
-
<span><kbd>drag</kbd> pan</span><span>·</span>
|
|
462
|
-
<span><kbd>scroll</kbd> zoom</span><span>·</span>
|
|
463
|
-
<span><kbd>click a project</kbd> open it</span><span>·</span>
|
|
464
|
-
<span><kbd>click empty sky</kbd> start one</span>
|
|
465
|
-
</div>
|
|
466
|
-
</div>
|
|
467
|
-
</div>
|
|
468
|
-
|
|
469
|
-
<!-- ── table sub-view — the same rows, the same filter, and the nav is still
|
|
470
|
-
overhead. The gate's table lost the projects door entirely. ── -->
|
|
471
|
-
<div class="wrap" id="sub-table-body" hidden style="padding-bottom:40px">
|
|
472
|
-
<table class="tbl">
|
|
473
|
-
<thead>
|
|
474
|
-
<tr>
|
|
475
|
-
<th class="colName">Project</th>
|
|
476
|
-
<th class="right" aria-sort="descending">Builders ▾</th>
|
|
477
|
-
<th class="colType">Type</th>
|
|
478
|
-
<th class="colTags">Tags</th>
|
|
479
|
-
<th class="right colStatus">Status</th>
|
|
480
|
-
<th class="colGo"></th>
|
|
481
|
-
</tr>
|
|
482
|
-
</thead>
|
|
483
|
-
<tbody id="rows">
|
|
484
|
-
<tr data-rel="builder" data-apex-only>
|
|
485
|
-
<td><span class="pname"><span class="pdot" style="--acc:var(--accent)"></span>
|
|
486
|
-
<span><span class="ptitle">Cloud Bongos</span> <span class="pill">this platform</span><br>
|
|
487
|
-
<span class="ptag">The AI-first build platform</span></span></span></td>
|
|
488
|
-
<td class="right num">24</td>
|
|
489
|
-
<td class="colType"><span class="pill">Platform</span></td>
|
|
490
|
-
<td class="colTags"><span class="tags"><span>platform</span><span>ai</span><span>build system</span></span></td>
|
|
491
|
-
<td class="right colStatus"><span class="chip calm"><span class="cdot"></span>—</span></td>
|
|
492
|
-
<td class="right colGo"><a class="btn small ghost" href="#">Enter →</a></td>
|
|
493
|
-
</tr>
|
|
494
|
-
<tr data-rel="owner">
|
|
495
|
-
<td><span class="pname"><span class="pdot" style="--acc:var(--sea)"></span>
|
|
496
|
-
<span><span class="ptitle">Off the Boats</span> <span class="pill">yours</span><br>
|
|
497
|
-
<span class="ptag">A painterly world you can walk into</span></span></span></td>
|
|
498
|
-
<td class="right num">6</td>
|
|
499
|
-
<td class="colType"><span class="pill">Live</span></td>
|
|
500
|
-
<td class="colTags"><span class="tags"><span>game</span><span>world</span></span></td>
|
|
501
|
-
<td class="right colStatus"><span class="chip live"><span class="cdot"></span>live <span class="rec">· 2m</span></span></td>
|
|
502
|
-
<td class="right colGo"><a class="btn small ghost" href="#">Manage →</a></td>
|
|
503
|
-
</tr>
|
|
504
|
-
<tr data-rel="builder">
|
|
505
|
-
<td><span class="pname"><span class="pdot" style="--acc:var(--terracotta)"></span>
|
|
506
|
-
<span><span class="ptitle">Emersonian Circles</span> <span class="pill">you build here</span><br>
|
|
507
|
-
<span class="ptag">Essays that talk back</span></span></span></td>
|
|
508
|
-
<td class="right num">2</td>
|
|
509
|
-
<td class="colType"><span class="pill">Live</span></td>
|
|
510
|
-
<td class="colTags"><span class="tags"><span>writing</span></span></td>
|
|
511
|
-
<td class="right colStatus"><span class="chip maybe"><span class="cdot"></span>live? <span class="rec">· 41m</span></span></td>
|
|
512
|
-
<td class="right colGo"><a class="btn small ghost" href="#">Manage →</a></td>
|
|
513
|
-
</tr>
|
|
514
|
-
<tr data-rel="none">
|
|
515
|
-
<td><span class="pname"><span class="pdot" style="--acc:var(--gold-soft)"></span>
|
|
516
|
-
<span><span class="ptitle">Demo</span><br>
|
|
517
|
-
<span class="ptag">A live demo instance on Cloud Bongos.</span></span></span></td>
|
|
518
|
-
<td class="right num">—</td>
|
|
519
|
-
<td class="colType"><span class="pill">Sample</span></td>
|
|
520
|
-
<td class="colTags"><span class="tags"><span>demo</span></span></td>
|
|
521
|
-
<td class="right colStatus"><span class="chip calm"><span class="cdot"></span>—</span></td>
|
|
522
|
-
<td class="right colGo"><a class="btn small ghost" href="#">Preview →</a></td>
|
|
523
|
-
</tr>
|
|
524
|
-
</tbody>
|
|
525
|
-
</table>
|
|
526
|
-
<p class="finePrint" style="text-align:center">Click a column to sort · click a row to open it.</p>
|
|
527
|
-
</div>
|
|
528
|
-
</section>
|
|
529
|
-
|
|
530
|
-
<!-- ══════════════════ VIEW · YOUR PROJECTS ══════════════════ -->
|
|
531
|
-
<section id="view-mine" hidden>
|
|
532
|
-
<div class="wrap" style="padding-bottom:40px">
|
|
533
|
-
<div class="hero" style="padding-left:0;padding-right:0">
|
|
534
|
-
<h1>Your projects</h1>
|
|
535
|
-
<p class="lede">Every project you own — what it is, whether it is answering, and the controls that matter.
|
|
536
|
-
Each card says what the platform <b>last verified</b>, and when.</p>
|
|
537
|
-
</div>
|
|
538
|
-
|
|
539
|
-
<!-- ★ .mineBar — search + state filter. The filter GROUPS the chip outcomes;
|
|
540
|
-
it never relabels them. "Live" holds both `live` and `live?` because
|
|
541
|
-
neither is known-down, and each card still says which it is (C6). -->
|
|
542
|
-
<div class="mineBar">
|
|
543
|
-
<div class="search">
|
|
544
|
-
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>
|
|
545
|
-
<input type="text" id="mineQ" placeholder="Search your projects by name, repo or address…">
|
|
546
|
-
<span class="count" id="mineCount">5 projects</span>
|
|
547
|
-
</div>
|
|
548
|
-
<div class="filters" role="group" aria-label="Filter by state">
|
|
549
|
-
<button data-f="all" aria-pressed="true">All <span class="n">5</span></button>
|
|
550
|
-
<button data-f="live" aria-pressed="false">Live <span class="n">2</span></button>
|
|
551
|
-
<button data-f="attention" aria-pressed="false">Needs you <span class="n">1</span></button>
|
|
552
|
-
<button data-f="working" aria-pressed="false">Working <span class="n">1</span></button>
|
|
553
|
-
<button data-f="gone" aria-pressed="false">Torn down <span class="n">1</span></button>
|
|
554
|
-
</div>
|
|
555
|
-
</div>
|
|
556
|
-
<p class="mineEmpty" id="mineEmpty" hidden>Nothing matches that. <button class="linklike" id="mineClear">Clear the filters</button></p>
|
|
557
|
-
|
|
558
|
-
<ul class="projects">
|
|
559
|
-
<li class="proj" data-state="live" data-find="off the boats lars589/off-the-boats offtheboats.com">
|
|
560
|
-
<span class="orb" style="--acc:var(--sea);--glow:rgba(15,122,150,.4)"></span>
|
|
561
|
-
<div class="projBody">
|
|
562
|
-
<div class="projHead">
|
|
563
|
-
<span class="projName">Off the Boats</span>
|
|
564
|
-
<span class="chip live"><span class="cdot"></span>live <span class="rec">· checked 2m ago</span></span>
|
|
565
|
-
</div>
|
|
566
|
-
<div class="projMeta"><span>repo <code>lars589/off-the-boats</code></span><span>its own box</span></div>
|
|
567
|
-
<p class="addr">Answering at <a href="#">offtheboats.com</a></p>
|
|
568
|
-
<div class="actions">
|
|
569
|
-
<a class="btn small" href="#">Open it</a>
|
|
570
|
-
<button class="btn small ghost">Tear it down</button>
|
|
571
|
-
</div>
|
|
572
|
-
</div>
|
|
573
|
-
</li>
|
|
574
|
-
|
|
575
|
-
<li class="proj" data-state="live" data-find="emersonian circles lars589/emersonian emersonian.cloudbongos.com">
|
|
576
|
-
<span class="orb dim" style="--acc:var(--terracotta);--glow:rgba(133,91,61,.4)"></span>
|
|
577
|
-
<div class="projBody">
|
|
578
|
-
<div class="projHead">
|
|
579
|
-
<span class="projName">Emersonian Circles</span>
|
|
580
|
-
<span class="chip maybe"><span class="cdot"></span>live? <span class="rec">· last seen 41m ago</span></span>
|
|
581
|
-
</div>
|
|
582
|
-
<div class="projMeta"><span>repo <code>lars589/emersonian</code></span><span>adopted repo</span></div>
|
|
583
|
-
<p class="addr">Its address is <a href="#">emersonian.cloudbongos.com</a> — confirming it answers.</p>
|
|
584
|
-
<div class="actions"><a class="btn small" href="#">Open it</a>
|
|
585
|
-
<button class="btn small ghost">Tear it down</button></div>
|
|
586
|
-
</div>
|
|
587
|
-
</li>
|
|
588
|
-
|
|
589
|
-
<li class="proj" data-state="attention" data-find="spike harbor lars589/spike-harbor spike-harbor.cloudbongos.com">
|
|
590
|
-
<span class="orb ashen" style="--acc:var(--accent);--glow:rgba(206,72,6,.4)"></span>
|
|
591
|
-
<div class="projBody">
|
|
592
|
-
<div class="projHead">
|
|
593
|
-
<span class="projName">Spike Harbor</span>
|
|
594
|
-
<span class="chip down"><span class="cdot"></span>unreachable <span class="rec">· since 14:20</span></span>
|
|
595
|
-
</div>
|
|
596
|
-
<div class="projMeta"><span>repo <code>lars589/spike-harbor</code></span><span>its own box</span></div>
|
|
597
|
-
<p class="addr">Not answering at <a href="#">spike-harbor.cloudbongos.com</a> right now.</p>
|
|
598
|
-
<div class="actions"><button class="btn small">Try again</button>
|
|
599
|
-
<button class="btn small ghost">Tear it down</button></div>
|
|
600
|
-
</div>
|
|
601
|
-
</li>
|
|
602
|
-
|
|
603
|
-
<li class="proj" data-state="working" data-find="mercury lars589/mercury">
|
|
604
|
-
<span class="orb dim" style="--acc:var(--gold-soft);--glow:rgba(246,201,118,.4)"></span>
|
|
605
|
-
<div class="projBody">
|
|
606
|
-
<div class="projHead">
|
|
607
|
-
<span class="projName">Mercury</span>
|
|
608
|
-
<span class="chip busy"><span class="cdot"></span>standing up</span>
|
|
609
|
-
</div>
|
|
610
|
-
<div class="projMeta"><span>repo <code>lars589/mercury</code></span><span>its own box</span></div>
|
|
611
|
-
<div class="strip">
|
|
612
|
-
<ul class="stages">
|
|
613
|
-
<li class="done"><span class="sdot"></span><span class="slbl">Request filed</span></li>
|
|
614
|
-
<li class="now"><span class="sdot"></span><span class="slbl">Standing it up</span></li>
|
|
615
|
-
<li><span class="sdot"></span><span class="slbl">Live</span></li>
|
|
616
|
-
</ul>
|
|
617
|
-
<p class="pnote">Its box is being built — this usually takes a few minutes.</p>
|
|
618
|
-
</div>
|
|
619
|
-
</div>
|
|
620
|
-
</li>
|
|
621
|
-
|
|
622
|
-
<li class="proj gone" data-state="gone" data-find="weeknight lars589/weeknight">
|
|
623
|
-
<span class="orb ghost" style="--acc:var(--ink-faint);--glow:transparent"></span>
|
|
624
|
-
<div class="projBody">
|
|
625
|
-
<div class="projHead">
|
|
626
|
-
<span class="projName">Weeknight</span>
|
|
627
|
-
<span class="chip calm"><span class="cdot"></span>torn down <span class="rec">· Aug 6</span></span>
|
|
628
|
-
</div>
|
|
629
|
-
<div class="projMeta"><span>repo <code>lars589/weeknight</code></span></div>
|
|
630
|
-
<div class="strip flowDown">
|
|
631
|
-
<ul class="stages">
|
|
632
|
-
<li class="done"><span class="sdot"></span><span class="slbl">Teardown queued</span></li>
|
|
633
|
-
<li class="done"><span class="sdot"></span><span class="slbl">Winding down</span></li>
|
|
634
|
-
<li class="done"><span class="sdot"></span><span class="slbl">Torn down</span></li>
|
|
635
|
-
</ul>
|
|
636
|
-
<p class="pnote">Its repo is untouched — bringing it back stands a fresh box up.</p>
|
|
637
|
-
</div>
|
|
638
|
-
<div class="actions"><button class="btn small ghost">Bring it back</button></div>
|
|
639
|
-
</div>
|
|
640
|
-
</li>
|
|
641
|
-
</ul>
|
|
642
|
-
</div>
|
|
643
|
-
</section>
|
|
644
|
-
|
|
645
|
-
<!-- ══════════════════ VIEW · NEW PROJECT ══════════════════ -->
|
|
646
|
-
<section id="view-new" hidden>
|
|
647
|
-
<div class="wrap" style="padding-bottom:40px;max-width:820px">
|
|
648
|
-
<div class="card">
|
|
649
|
-
<ol class="steps">
|
|
650
|
-
<li class="now"><span class="snum">1</span><span class="slbl">Name</span></li>
|
|
651
|
-
<li><span class="snum">2</span><span class="slbl">Home</span></li>
|
|
652
|
-
<li><span class="snum">3</span><span class="slbl">Address</span></li>
|
|
653
|
-
<li><span class="snum">4</span><span class="slbl">Create</span></li>
|
|
654
|
-
</ol>
|
|
655
|
-
|
|
656
|
-
<div class="createSplit">
|
|
657
|
-
<div>
|
|
658
|
-
<h1 style="font-family:var(--font-display);font-size:var(--fs-h2);letter-spacing:-.5px;margin-bottom:10px">
|
|
659
|
-
Start a project</h1>
|
|
660
|
-
<p class="lede">Your own project: its own repository, its own home on the web, and a hall of AI builders
|
|
661
|
-
who do the building. You set the direction; agents lay down the code.</p>
|
|
662
|
-
<div class="attach">
|
|
663
|
-
<input type="text" placeholder="What should it be called?">
|
|
664
|
-
</div>
|
|
665
|
-
<div class="actions"><button class="btn">Continue →</button>
|
|
666
|
-
<button class="btn ghost small">Cancel</button></div>
|
|
667
|
-
<p class="finePrint">Free while we find our feet. Your project’s repo and server are yours —
|
|
668
|
-
Cloud Bongos is <a href="#" style="color:var(--accent-deep);font-weight:700">open source (AGPL-3.0)</a>
|
|
669
|
-
and capture-resistant by design.</p>
|
|
670
|
-
</div>
|
|
671
|
-
|
|
672
|
-
<!-- the bongo pair — one mark on every surface (owner, 2026-08-13).
|
|
673
|
-
Reused from public-landing/index.html:250-323, static pose here. -->
|
|
674
|
-
<div class="bongoCell">
|
|
675
|
-
<svg class="bongos" viewBox="0 0 440 320" role="img" aria-label="A pair of bongo drums">
|
|
676
|
-
<defs>
|
|
677
|
-
<linearGradient id="shellBig" x1="0" y1="0" x2="1" y2="0.35">
|
|
678
|
-
<stop offset="0%" stop-color="var(--accent-deep)"/><stop offset="16%" stop-color="var(--accent)"/>
|
|
679
|
-
<stop offset="48%" stop-color="var(--accent)"/><stop offset="86%" stop-color="var(--accent-deep)"/>
|
|
680
|
-
<stop offset="100%" stop-color="var(--accent-deep)"/>
|
|
681
|
-
</linearGradient>
|
|
682
|
-
<linearGradient id="shellSml" x1="0" y1="0" x2="1" y2="0.35">
|
|
683
|
-
<stop offset="0%" stop-color="var(--accent-deep)"/><stop offset="18%" stop-color="var(--terracotta)"/>
|
|
684
|
-
<stop offset="55%" stop-color="var(--terracotta)"/><stop offset="100%" stop-color="var(--accent-deep)"/>
|
|
685
|
-
</linearGradient>
|
|
686
|
-
<radialGradient id="skin" cx="0.36" cy="0.26" r="0.9">
|
|
687
|
-
<stop offset="0%" stop-color="var(--skin-hi)"/><stop offset="58%" stop-color="var(--skin-mid)"/>
|
|
688
|
-
<stop offset="100%" stop-color="var(--skin-lo)"/>
|
|
689
|
-
</radialGradient>
|
|
690
|
-
<radialGradient id="halo" cx="0.5" cy="0.5" r="0.5">
|
|
691
|
-
<stop offset="0%" stop-color="var(--accent)" stop-opacity="0.30"/>
|
|
692
|
-
<stop offset="48%" stop-color="var(--accent)" stop-opacity="0.13"/>
|
|
693
|
-
<stop offset="100%" stop-color="var(--accent)" stop-opacity="0"/>
|
|
694
|
-
</radialGradient>
|
|
695
|
-
<filter id="soft" x="-60%" y="-160%" width="220%" height="420%"><feGaussianBlur stdDeviation="9"/></filter>
|
|
696
|
-
</defs>
|
|
697
|
-
<ellipse class="glow" cx="222" cy="170" rx="215" ry="140" fill="url(#halo)"/>
|
|
698
|
-
<ellipse class="bshadow" cx="220" cy="286" rx="142" ry="14" fill="var(--drum-shadow)" opacity=".22" filter="url(#soft)"/>
|
|
699
|
-
<path d="M 214,196 C 232,188 250,188 264,196 L 258,232 C 244,225 230,225 219,232 Z" fill="var(--accent-deep)"/>
|
|
700
|
-
<path d="M 214,196 C 232,188 250,188 264,196 L 262,205 C 247,197 231,197 216,205 Z" fill="var(--ink)" opacity=".22"/>
|
|
701
|
-
<g class="drumBig">
|
|
702
|
-
<path d="M 74,118 C 76,166 90,228 98,266 A 52,17 0 0 0 202,266 C 210,228 224,166 226,118 Z" fill="url(#shellBig)"/>
|
|
703
|
-
<path d="M 172,124 C 174,176 186,232 192,268 A 52,17 0 0 0 202,266 C 210,228 224,166 226,118 Z" fill="var(--ink)" opacity=".17"/>
|
|
704
|
-
<path d="M 92,126 C 94,174 104,230 110,266 A 52,17 0 0 1 100,267 C 92,230 78,172 76,124 Z" fill="#fff" opacity=".20"/>
|
|
705
|
-
<ellipse cx="150" cy="121" rx="80" ry="29" fill="var(--accent-deep)"/>
|
|
706
|
-
<ellipse cx="150" cy="117" rx="80" ry="29" fill="var(--accent)"/>
|
|
707
|
-
<ellipse cx="150" cy="117" rx="80" ry="29" fill="#fff" opacity=".13"/>
|
|
708
|
-
<ellipse cx="150" cy="118" rx="70" ry="24" fill="url(#skin)"/>
|
|
709
|
-
<ellipse cx="150" cy="118" rx="70" ry="24" fill="none" stroke="var(--ink)" stroke-opacity=".09" stroke-width="1.4"/>
|
|
710
|
-
<ellipse cx="150" cy="118" rx="55" ry="18" fill="none" stroke="var(--ink)" stroke-opacity=".045" stroke-width="1"/>
|
|
711
|
-
<g fill="var(--accent-deep)">
|
|
712
|
-
<path d="M 78,138 l 9,0 -1.5,20 -6,0 z"/><path d="M 120,148 l 9,0 -1,21 -7,0 z"/>
|
|
713
|
-
<path d="M 172,148 l 9,0 -1,21 -7,0 z"/><path d="M 214,138 l 9,0 -1.5,20 -6,0 z"/>
|
|
714
|
-
</g>
|
|
715
|
-
</g>
|
|
716
|
-
<g class="drumSml">
|
|
717
|
-
<path d="M 240,134 C 242,178 252,230 258,266 A 40,13 0 0 0 338,266 C 344,230 354,178 356,134 Z" fill="url(#shellSml)"/>
|
|
718
|
-
<path d="M 314,140 C 316,186 324,234 328,268 A 40,13 0 0 0 338,266 C 344,230 354,178 356,134 Z" fill="var(--ink)" opacity=".19"/>
|
|
719
|
-
<path d="M 254,140 C 256,182 264,232 268,266 A 40,13 0 0 1 260,267 C 254,232 244,182 242,138 Z" fill="#fff" opacity=".17"/>
|
|
720
|
-
<ellipse cx="296" cy="137" rx="60" ry="22" fill="var(--accent-deep)"/>
|
|
721
|
-
<ellipse cx="296" cy="133" rx="60" ry="22" fill="var(--terracotta)"/>
|
|
722
|
-
<ellipse cx="296" cy="133" rx="60" ry="22" fill="#fff" opacity=".13"/>
|
|
723
|
-
<ellipse cx="296" cy="134" rx="51" ry="18" fill="url(#skin)"/>
|
|
724
|
-
<ellipse cx="296" cy="134" rx="51" ry="18" fill="none" stroke="var(--ink)" stroke-opacity=".09" stroke-width="1.4"/>
|
|
725
|
-
<ellipse cx="296" cy="134" rx="39" ry="13" fill="none" stroke="var(--ink)" stroke-opacity=".045" stroke-width="1"/>
|
|
726
|
-
<g fill="var(--accent-deep)">
|
|
727
|
-
<path d="M 243,152 l 8,0 -1,17 -6,0 z"/><path d="M 276,160 l 8,0 -1,18 -6,0 z"/>
|
|
728
|
-
<path d="M 312,160 l 8,0 -1,18 -6,0 z"/><path d="M 345,152 l 8,0 -1,17 -6,0 z"/>
|
|
729
|
-
</g>
|
|
730
|
-
</g>
|
|
731
|
-
</svg>
|
|
732
|
-
</div>
|
|
733
|
-
</div>
|
|
734
|
-
</div>
|
|
735
|
-
|
|
736
|
-
<!-- a child instance does not provision: say so rather than fall into the
|
|
737
|
-
generic "Couldn't read your projects right now" alert (§0 defect 3). -->
|
|
738
|
-
<div class="fieldNote" id="childNote" style="margin-top:22px;display:none">
|
|
739
|
-
Projects aren’t created from this instance — this is a project, not the platform that hosts them.
|
|
740
|
-
</div>
|
|
741
|
-
</div>
|
|
742
|
-
</section>
|
|
743
|
-
|
|
744
|
-
<p class="foot">
|
|
745
|
-
<span data-apex-only>A non-profit, capture-resistant commons. </span>Built by agents, on Cloud Bongos.
|
|
746
|
-
</p>
|
|
747
|
-
|
|
748
|
-
<!-- MOCK-ONLY CONTROL RAIL — not part of the design -->
|
|
749
|
-
<div class="rail">
|
|
750
|
-
<b>ground</b>
|
|
751
|
-
<button data-g="a">A framed</button>
|
|
752
|
-
<button data-g="b" aria-pressed="true">B dual-mode</button>
|
|
753
|
-
<button data-g="c">C deep space</button>
|
|
754
|
-
<span class="sep"></span>
|
|
755
|
-
<b>view</b>
|
|
756
|
-
<button data-v="map" aria-pressed="true">Map</button>
|
|
757
|
-
<button data-v="mine">Yours</button>
|
|
758
|
-
<button data-v="new">New</button>
|
|
759
|
-
<span class="sep"></span>
|
|
760
|
-
<button id="r-mode">☾ mode</button>
|
|
761
|
-
<button id="r-signed" aria-pressed="true">signed in</button>
|
|
762
|
-
<button id="r-real" title="GET /my-projects returns { owned: [], building: [] } today">real memberships</button>
|
|
763
|
-
<button id="r-apex">S outline</button>
|
|
764
|
-
<button id="r-child">C child</button>
|
|
765
|
-
</div>
|
|
766
|
-
|
|
767
|
-
<script>
|
|
768
|
-
/* ── mock behaviour only. The shipping page's real logic is not modelled;
|
|
769
|
-
this exists so the owner can walk the surface. ── */
|
|
770
|
-
(function () {
|
|
771
|
-
var $ = function (s) { return document.querySelector(s); };
|
|
772
|
-
var $$ = function (s) { return Array.prototype.slice.call(document.querySelectorAll(s)); };
|
|
773
|
-
var html = document.documentElement, body = document.body;
|
|
774
|
-
|
|
775
|
-
if (new URLSearchParams(location.search).get('rail') === '0') body.classList.add('rail-off');
|
|
776
|
-
|
|
777
|
-
/* the self-typing wordmark — the one gate flourish that survives (owner
|
|
778
|
-
disposition). Cycles what you might type into an AI to reach this. */
|
|
779
|
-
var WORDS = ['bongos', 'claude', 'gemini', 'copilot'], wi = 0, ci = 6, dir = -1;
|
|
780
|
-
var typed = $('#typed');
|
|
781
|
-
var reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
782
|
-
if (!reduce) setInterval(function () {
|
|
783
|
-
var w = WORDS[wi];
|
|
784
|
-
ci += dir;
|
|
785
|
-
if (ci <= 0) { dir = 1; wi = (wi + 1) % WORDS.length; ci = 0; }
|
|
786
|
-
else if (ci >= WORDS[wi].length) { dir = -1; ci = WORDS[wi].length; }
|
|
787
|
-
typed.textContent = WORDS[wi].slice(0, ci);
|
|
788
|
-
}, 190);
|
|
789
|
-
|
|
790
|
-
/* ground */
|
|
791
|
-
function setGround(g) {
|
|
792
|
-
html.setAttribute('data-ground', g);
|
|
793
|
-
try { localStorage.setItem('cb-mock-ground', g); } catch (e) {}
|
|
794
|
-
$$('[data-g]').forEach(function (b) { b.setAttribute('aria-pressed', String(b.dataset.g === g)); });
|
|
795
|
-
}
|
|
796
|
-
$$('[data-g]').forEach(function (b) { b.onclick = function () { setGround(b.dataset.g); }; });
|
|
797
|
-
setGround(html.getAttribute('data-ground') || 'b');
|
|
798
|
-
|
|
799
|
-
/* views — ?view= is the deep-link contract the build adopts (map|mine|new) */
|
|
800
|
-
function setView(v) {
|
|
801
|
-
['map', 'mine', 'new'].forEach(function (k) { $('#view-' + k).hidden = (k !== v); });
|
|
802
|
-
$$('[data-nav]').forEach(function (a) {
|
|
803
|
-
if (a.dataset.nav === v) a.setAttribute('aria-current', 'page'); else a.removeAttribute('aria-current');
|
|
804
|
-
});
|
|
805
|
-
$$('[data-v]').forEach(function (b) { b.setAttribute('aria-pressed', String(b.dataset.v === v)); });
|
|
806
|
-
history.replaceState(null, '', '?view=' + v + (body.classList.contains('rail-off') ? '&rail=0' : ''));
|
|
807
|
-
}
|
|
808
|
-
$$('[data-v]').forEach(function (b) { b.onclick = function () { setView(b.dataset.v); }; });
|
|
809
|
-
/* Home is a real navigation to /, not a view swap — leave its default alone.
|
|
810
|
-
In the mock that would leave the file, so it is neutralised with a note. */
|
|
811
|
-
$$('[data-nav]').forEach(function (a) {
|
|
812
|
-
if (a.dataset.nav === 'home') {
|
|
813
|
-
a.onclick = function (e) { e.preventDefault(); alert('Goes to / — the landing page. Not mocked here.'); };
|
|
814
|
-
return;
|
|
815
|
-
}
|
|
816
|
-
a.onclick = function (e) { e.preventDefault(); setView(a.dataset.nav); };
|
|
817
|
-
});
|
|
818
|
-
setView(new URLSearchParams(location.search).get('view') || 'map');
|
|
819
|
-
|
|
820
|
-
/* sky | table */
|
|
821
|
-
function setSub(which) {
|
|
822
|
-
$('#sub-sky').setAttribute('aria-pressed', String(which === 'sky'));
|
|
823
|
-
$('#sub-table').setAttribute('aria-pressed', String(which === 'table'));
|
|
824
|
-
$('#sub-sky-body').hidden = which !== 'sky';
|
|
825
|
-
$('#sub-table-body').hidden = which !== 'table';
|
|
826
|
-
}
|
|
827
|
-
$('#sub-sky').onclick = function () { setSub('sky'); };
|
|
828
|
-
$('#sub-table').onclick = function () { setSub('table'); };
|
|
829
|
-
|
|
830
|
-
/* ── the only-mine filter — ONE control, BOTH views (owner, 2026-08-13).
|
|
831
|
-
"Mine" = a membership row with role owner OR builder, which is exactly the
|
|
832
|
-
{ owned, building } split GET /my-projects already returns. Ownership is
|
|
833
|
-
NOT read off projects.owner_github_id — that column is documented as
|
|
834
|
-
"advisory attribution (not an authority)" in the catalog migration. ── */
|
|
835
|
-
var MINE = { owner: 1, builder: 1 };
|
|
836
|
-
/* every element remembers the relationship it was authored with, so the rail
|
|
837
|
-
can swap the whole page to the live truth and back without losing it */
|
|
838
|
-
$$('[data-rel]').forEach(function (el) { el.dataset.relOrig = el.dataset.rel; });
|
|
839
|
-
function relOf(el) { return el.dataset.rel || 'none'; }
|
|
840
|
-
|
|
841
|
-
function applyFilter() {
|
|
842
|
-
var on = $('#onlyMine').checked, n = 0;
|
|
843
|
-
$$('.worldOrb').forEach(function (o) {
|
|
844
|
-
var keep = !on || MINE[relOf(o)];
|
|
845
|
-
o.style.display = keep ? '' : 'none';
|
|
846
|
-
if (keep) n++;
|
|
847
|
-
});
|
|
848
|
-
$$('#rows tr').forEach(function (r) {
|
|
849
|
-
r.hidden = on && !MINE[relOf(r)];
|
|
850
|
-
});
|
|
851
|
-
/* the badge must never claim more than the membership row says */
|
|
852
|
-
$$('.worldOrb').forEach(function (o) {
|
|
853
|
-
var b = o.querySelector('.badge'), rel = relOf(o);
|
|
854
|
-
if (!b) return;
|
|
855
|
-
if (o.hasAttribute('data-apex-only') && rel === 'none') b.textContent = 'this platform';
|
|
856
|
-
else if (rel === 'owner') b.textContent = 'yours';
|
|
857
|
-
else if (rel === 'builder') b.textContent = 'you build here';
|
|
858
|
-
else b.hidden = true;
|
|
859
|
-
if (rel !== 'none') b.hidden = false;
|
|
860
|
-
});
|
|
861
|
-
$('.field').classList.toggle('isEmpty', on && n === 0);
|
|
862
|
-
$('#count').textContent = n + (n === 1 ? ' project' : ' projects');
|
|
863
|
-
}
|
|
864
|
-
$('#onlyMine').onchange = applyFilter;
|
|
865
|
-
|
|
866
|
-
/* rail: flip the mock between illustrative memberships and the LIVE truth —
|
|
867
|
-
GET /my-projects returns { owned: [], building: [] } for this account today,
|
|
868
|
-
so "real" means every orb goes unaffiliated and the filter empties. */
|
|
869
|
-
$('#r-real').onclick = function () {
|
|
870
|
-
var real = this.getAttribute('aria-pressed') !== 'true';
|
|
871
|
-
this.setAttribute('aria-pressed', String(real));
|
|
872
|
-
$$('[data-rel]').forEach(function (el) {
|
|
873
|
-
el.dataset.rel = real ? 'none' : el.dataset.relOrig;
|
|
874
|
-
});
|
|
875
|
-
$('#emptyMsg').textContent = real
|
|
876
|
-
? 'You don’t own or build on anything here yet.'
|
|
877
|
-
: 'Nothing here is yours yet.';
|
|
878
|
-
applyFilter();
|
|
879
|
-
};
|
|
880
|
-
|
|
881
|
-
/* ── Your projects: search + state filter ──────────────────────────────────
|
|
882
|
-
The filter GROUPS chip outcomes, it never relabels them: "Live" holds both
|
|
883
|
-
`live` and `live?` because neither is known-down, and each card still says
|
|
884
|
-
which it is. Counts are computed from the cards so a state with nothing in
|
|
885
|
-
it reads 0 before you click it rather than after. */
|
|
886
|
-
var mineFilter = 'all';
|
|
887
|
-
|
|
888
|
-
function applyMine() {
|
|
889
|
-
var q = $('#mineQ').value.trim().toLowerCase();
|
|
890
|
-
var shown = 0;
|
|
891
|
-
$$('#view-mine .proj').forEach(function (li) {
|
|
892
|
-
var okState = mineFilter === 'all' || li.dataset.state === mineFilter;
|
|
893
|
-
var okQ = !q || (li.dataset.find || '').indexOf(q) !== -1;
|
|
894
|
-
var keep = okState && okQ;
|
|
895
|
-
li.hidden = !keep;
|
|
896
|
-
if (keep) shown++;
|
|
897
|
-
});
|
|
898
|
-
$('#mineCount').textContent = shown + (shown === 1 ? ' project' : ' projects');
|
|
899
|
-
$('#mineEmpty').hidden = shown !== 0;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
function recountMine() {
|
|
903
|
-
var q = $('#mineQ').value.trim().toLowerCase();
|
|
904
|
-
var tally = { all: 0 };
|
|
905
|
-
$$('#view-mine .proj').forEach(function (li) {
|
|
906
|
-
if (q && (li.dataset.find || '').indexOf(q) === -1) return;
|
|
907
|
-
var st = li.dataset.state;
|
|
908
|
-
tally.all++;
|
|
909
|
-
tally[st] = (tally[st] || 0) + 1;
|
|
910
|
-
});
|
|
911
|
-
$$('.filters button').forEach(function (b) {
|
|
912
|
-
b.querySelector('.n').textContent = tally[b.dataset.f] || 0;
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
$$('.filters button').forEach(function (b) {
|
|
917
|
-
b.onclick = function () {
|
|
918
|
-
mineFilter = b.dataset.f;
|
|
919
|
-
$$('.filters button').forEach(function (o) {
|
|
920
|
-
o.setAttribute('aria-pressed', String(o === b));
|
|
921
|
-
});
|
|
922
|
-
applyMine();
|
|
923
|
-
};
|
|
924
|
-
});
|
|
925
|
-
$('#mineQ').oninput = function () { recountMine(); applyMine(); };
|
|
926
|
-
$('#mineClear').onclick = function () {
|
|
927
|
-
$('#mineQ').value = '';
|
|
928
|
-
mineFilter = 'all';
|
|
929
|
-
$$('.filters button').forEach(function (o) {
|
|
930
|
-
o.setAttribute('aria-pressed', String(o.dataset.f === 'all'));
|
|
931
|
-
});
|
|
932
|
-
recountMine(); applyMine();
|
|
933
|
-
};
|
|
934
|
-
recountMine(); applyMine();
|
|
935
|
-
|
|
936
|
-
/* mode */
|
|
937
|
-
function toggleMode() {
|
|
938
|
-
var cur = html.getAttribute('data-mode');
|
|
939
|
-
if (!cur) cur = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
940
|
-
var next = cur === 'dark' ? 'light' : 'dark';
|
|
941
|
-
html.setAttribute('data-mode', next);
|
|
942
|
-
try { localStorage.setItem('cb-color-mode', next); } catch (e) {}
|
|
943
|
-
$('#mode').textContent = next === 'dark' ? '☀' : '☾';
|
|
944
|
-
}
|
|
945
|
-
$('#mode').onclick = toggleMode;
|
|
946
|
-
$('#r-mode').onclick = toggleMode;
|
|
947
|
-
|
|
948
|
-
/* signed-in / signed-out — the nav never renders a door it has not earned */
|
|
949
|
-
$('#r-signed').onclick = function () {
|
|
950
|
-
var on = this.getAttribute('aria-pressed') !== 'true';
|
|
951
|
-
this.setAttribute('aria-pressed', String(on));
|
|
952
|
-
$('#who').hidden = !on;
|
|
953
|
-
$('#signin').hidden = on;
|
|
954
|
-
$('[data-nav="mine"]').style.display = on ? '' : 'none';
|
|
955
|
-
$('#onlyMine').closest('.switch').style.display = on ? '' : 'none';
|
|
956
|
-
if (!on) { $('#onlyMine').checked = false; applyFilter(); }
|
|
957
|
-
};
|
|
958
|
-
|
|
959
|
-
/* apex-only outline + child preview */
|
|
960
|
-
function toggleApex() { body.classList.toggle('show-apex'); }
|
|
961
|
-
function toggleChild() {
|
|
962
|
-
body.classList.toggle('child-preview');
|
|
963
|
-
$('#childNote').style.display = body.classList.contains('child-preview') ? '' : 'none';
|
|
964
|
-
}
|
|
965
|
-
$('#r-apex').onclick = toggleApex;
|
|
966
|
-
$('#r-child').onclick = toggleChild;
|
|
967
|
-
|
|
968
|
-
document.addEventListener('keydown', function (e) {
|
|
969
|
-
if (e.target.tagName === 'INPUT') return;
|
|
970
|
-
var k = e.key.toLowerCase();
|
|
971
|
-
if (k === 's') toggleApex();
|
|
972
|
-
if (k === 'c') toggleChild();
|
|
973
|
-
if (k === '1') setView('map');
|
|
974
|
-
if (k === '2') setView('mine');
|
|
975
|
-
if (k === '3') setView('new');
|
|
976
|
-
});
|
|
977
|
-
|
|
978
|
-
/* starfield — only paints where --star-display is block */
|
|
979
|
-
var sf = $('#stars'), frag = document.createDocumentFragment();
|
|
980
|
-
for (var i = 0; i < 90; i++) {
|
|
981
|
-
var s = document.createElement('i');
|
|
982
|
-
s.style.left = (Math.random() * 100).toFixed(2) + '%';
|
|
983
|
-
s.style.top = (Math.random() * 100).toFixed(2) + '%';
|
|
984
|
-
s.style.opacity = (0.25 + Math.random() * 0.5).toFixed(2);
|
|
985
|
-
frag.appendChild(s);
|
|
986
|
-
}
|
|
987
|
-
sf.appendChild(frag);
|
|
988
|
-
})();
|
|
989
|
-
</script>
|
|
990
|
-
</body>
|
|
991
|
-
</html>
|