@bongos/core 1.18.3 → 1.18.18
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 +1575 -285
- package/.claude/skills/builder-box/SKILL.md +6 -0
- package/.claude/skills/builder-sequence/SKILL.md +97 -0
- package/.claude/skills/builder-ship/SKILL.md +8 -2
- package/.claude/skills/builder-start/SKILL.md +11 -0
- package/.claude/skills/builder-sync/SKILL.md +41 -0
- package/.claude/skills/fix-task/SKILL.md +64 -0
- package/.claude/skills/goal-create/SKILL.md +158 -0
- package/.claude/skills/goal-review/SKILL.md +3 -1
- package/.claude/skills/idea-triage/SKILL.md +14 -8
- package/.claude/skills/merge-mode/SKILL.md +2 -2
- package/.claude/skills/new-project/SKILL.md +1 -0
- package/.claude/skills/planning-session/SKILL.md +45 -18
- package/.env.local.example +4 -3
- package/README.md +4 -2
- package/bin/bongos.js +1 -0
- package/clients/bongos-client/README.md +2 -2
- package/clients/bongos-client/bongos-client.global.js +82 -18
- package/clients/bongos-client/index.cjs +82 -18
- package/clients/bongos-client/index.d.ts +131 -29
- package/clients/bongos-client/index.mjs +82 -18
- package/config/branding.neutral.json +6 -1
- package/config/governance.neutral.json +21 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
- package/docs/adr/0090-metic-task-authoring.md +1 -1
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
- package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
- package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
- package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
- package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
- package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
- package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
- package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
- package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
- package/docs/adr/0152-metic-task-abandonment.md +67 -0
- package/docs/adr/0153-sequential-chain-runner.md +51 -0
- package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
- package/docs/adr/README.md +10 -0
- package/docs/api/openapi.json +843 -17
- package/docs/api-reference.md +23 -10
- package/docs/architecture.md +4 -2
- package/docs/branding-contract.md +3 -1
- package/docs/canonical-permissions.md +21 -8
- package/docs/file-map.md +8 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
- package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
- package/docs/onboarding/diagrams/assertions.json +4 -7
- package/docs/onboarding/drachmae-and-karma.md +3 -3
- package/docs/onboarding/primer.md +17 -16
- package/docs/onboarding/slash-commands.md +124 -0
- package/docs/recipes/builder-box-lifecycle.md +23 -0
- package/docs/recipes/devbox-app-release.md +14 -4
- package/docs/recipes/instance-first-run.md +16 -0
- package/docs/recipes/local-dev.md +81 -0
- package/docs/recipes/ops-gotchas.md +19 -1
- package/docs/recipes/overnight-builder.md +1 -1
- package/docs/recipes/parallel-goal-waves.md +174 -0
- package/docs/recipes/ship-and-regrade.md +2 -2
- package/docs/recipes/standalone-live-docs.md +48 -0
- package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
- package/migrations/003_pms.sql +6 -7
- package/migrations/006_pms_v2.sql +3 -31
- package/migrations/core_193_task_needs_rebase.sql +28 -0
- package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
- package/migrations/core_195_idea_triage_provenance.sql +57 -0
- package/migrations/core_196_session_reward_topup.sql +69 -0
- package/modules/autonomy/pollers/routine-timers.js +9 -8
- package/modules/builder-settings/wandering-prefs.js +61 -18
- package/modules/dev-box/app/README.md +73 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
- package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
- package/modules/dev-box/app/assets/tray/win-off.png +0 -0
- package/modules/dev-box/app/assets/tray/win-on.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
- package/modules/dev-box/app/build-resources/icon.png +0 -0
- package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
- package/modules/dev-box/app/electron-builder.yml +95 -0
- package/modules/dev-box/app/package-lock.json +5291 -0
- package/modules/dev-box/app/package.json +30 -0
- package/modules/dev-box/app/renderer/app.js +319 -0
- package/modules/dev-box/app/renderer/index.html +45 -0
- package/modules/dev-box/app/renderer/styles.css +246 -0
- package/modules/dev-box/app/renderer/theme.generated.css +16 -0
- package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
- package/modules/dev-box/app/scripts/gen-brand.js +138 -0
- package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
- package/modules/dev-box/app/scripts/gen-icons.js +286 -0
- package/modules/dev-box/app/scripts/vendor-client.js +23 -0
- package/modules/dev-box/app/src/box-controller.js +287 -0
- package/modules/dev-box/app/src/brand.generated.json +13 -0
- package/modules/dev-box/app/src/brand.js +16 -0
- package/modules/dev-box/app/src/config.js +19 -0
- package/modules/dev-box/app/src/gds-client.js +90 -0
- package/modules/dev-box/app/src/main.js +610 -0
- package/modules/dev-box/app/src/pairing.js +57 -0
- package/modules/dev-box/app/src/preload.js +29 -0
- package/modules/dev-box/app/src/session-store.js +58 -0
- package/modules/dev-box/app/src/ssh-setup.js +569 -0
- package/modules/dev-box/app/src/task-picker.js +70 -0
- package/modules/dev-box/app/src/tray.js +99 -0
- package/modules/dev-box/app/src/updater.js +55 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
- package/modules/dev-box/app/test/unit.mjs +526 -0
- package/modules/dev-box/box-access.js +121 -4
- package/modules/dev-box/boxes.js +20 -0
- package/modules/dev-box/module.json +1 -1
- package/modules/dev-box/routes/box.js +87 -3
- package/modules/economy/credits.js +116 -25
- package/modules/economy/reward.js +8 -0
- package/modules/economy/streak.js +2 -1
- package/modules/governance/CLAUDE.md +15 -0
- package/modules/governance/catalog.js +419 -0
- package/modules/governance/config.js +174 -0
- package/modules/governance/db.js +125 -0
- package/modules/governance/migrations/governance_001_tables.sql +81 -0
- package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
- package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
- package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
- package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
- package/modules/governance/module.json +10 -0
- package/modules/governance/protected-surfaces.js +88 -0
- package/modules/governance/protected-surfaces.json +80 -0
- package/modules/governance/rank-roles.js +83 -0
- package/modules/governance/resolver.js +221 -0
- package/modules/governance/routes/governance.js +89 -0
- package/modules/governance/routes/role-sync.js +49 -0
- package/modules/governance/session-scopes.js +127 -0
- package/modules/governance/session-scopes.json +38 -0
- package/modules/hall-ui/public/atlas.css +117 -0
- package/modules/hall-ui/public/atlas.html +3 -114
- package/modules/hall-ui/public/brand-apply.js +34 -6
- package/modules/hall-ui/public/builders.js +187 -219
- package/modules/hall-ui/public/diagrams.html +2 -0
- package/modules/hall-ui/public/dom-utils.js +27 -0
- package/modules/hall-ui/public/drachmae.html +2 -0
- package/modules/hall-ui/public/drachmae.js +54 -1
- package/modules/hall-ui/public/gate.css +98 -0
- package/modules/hall-ui/public/gate.html +3 -95
- package/modules/hall-ui/public/goal-inbox.js +4 -1
- package/modules/hall-ui/public/goals-page.js +626 -114
- package/modules/hall-ui/public/goals.css +79 -1
- package/modules/hall-ui/public/goals.html +38 -11
- package/modules/hall-ui/public/hall-widgets.js +62 -52
- package/modules/hall-ui/public/harbor.css +123 -0
- package/modules/hall-ui/public/harbor.html +3 -120
- package/modules/hall-ui/public/index.html +11 -4
- package/modules/hall-ui/public/instances-panel.js +4 -1
- package/modules/hall-ui/public/modules.css +63 -0
- package/modules/hall-ui/public/modules.html +3 -60
- package/modules/hall-ui/public/new-project-wizard.js +7 -3
- package/modules/hall-ui/public/not-ready.html +2 -0
- package/modules/hall-ui/public/pair.css +73 -0
- package/modules/hall-ui/public/pair.html +3 -70
- package/modules/hall-ui/public/palette.js +302 -0
- package/modules/hall-ui/public/primer.css +13 -0
- package/modules/hall-ui/public/primer.html +2 -0
- package/modules/hall-ui/public/profile.html +2 -0
- package/modules/hall-ui/public/ranks.html +2 -0
- package/modules/hall-ui/public/roadmap.css +179 -0
- package/modules/hall-ui/public/roadmap.html +9 -172
- package/modules/hall-ui/public/roadmap.js +329 -316
- package/modules/hall-ui/public/sessions.css +16 -0
- package/modules/hall-ui/public/sessions.html +3 -13
- package/modules/hall-ui/public/settings.html +2 -0
- package/modules/hall-ui/public/settings.js +4 -4
- package/modules/hall-ui/public/shell.js +143 -18
- package/modules/hall-ui/public/style.css +231 -39
- package/modules/hall-ui/public/task-detail.js +347 -26
- package/modules/hall-ui/public/task.html +6 -1
- package/modules/hall-ui/public/watch.html +2 -0
- package/modules/hall-ui/public/work.html +8 -6
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/ideas/inbox.js +61 -11
- package/modules/ideas/routes/inbox.js +23 -0
- package/modules/lifecycle/claim-eligibility.js +72 -0
- package/modules/lifecycle/db.js +519 -139
- package/modules/lifecycle/done-when.js +18 -3
- package/modules/lifecycle/github-push.js +19 -2
- package/modules/lifecycle/goal-advisory.js +114 -0
- package/modules/lifecycle/goal-authz.js +62 -0
- package/modules/lifecycle/lifecycle.js +9 -0
- package/modules/lifecycle/publish-reconciler.js +109 -6
- package/modules/lifecycle/routes/claims.js +68 -23
- package/modules/lifecycle/routes/done-when.js +110 -15
- package/modules/lifecycle/routes/goals.js +8 -38
- package/modules/lifecycle/routes/tasks.js +38 -6
- package/modules/lifecycle/ship-card.js +6 -0
- package/modules/onboarding/onboarding-state.js +1 -1
- package/modules/platform-identity/CLAUDE.md +15 -0
- package/modules/platform-identity/hub-device.js +147 -0
- package/modules/platform-identity/hub-keys.js +151 -0
- package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
- package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
- package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
- package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
- package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
- package/modules/platform-identity/module.json +18 -0
- package/modules/platform-identity/platform-identity.js +531 -0
- package/modules/platform-identity/pollers/code-sweep.js +43 -0
- package/modules/platform-identity/routes/my-projects.js +140 -0
- package/modules/platform-identity/routes/projects.js +107 -0
- package/modules/platform-identity/routes/scouting.js +35 -0
- package/modules/platform-identity/routes/sso.js +402 -0
- package/modules/platform-identity/tests/platform-identity.mjs +388 -0
- package/modules/platform-identity/ui/.gitkeep +0 -0
- package/modules/security/routes/reports.js +10 -0
- package/modules/sessions/db.js +166 -21
- package/modules/sessions/module.json +1 -1
- package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
- package/modules/sessions/routes/sessions.js +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/anim/idle/frame_00.webp +0 -0
- package/public-landing/assets/anim/idle/frame_01.webp +0 -0
- package/public-landing/assets/anim/idle/frame_02.webp +0 -0
- package/public-landing/assets/anim/idle/frame_03.webp +0 -0
- package/public-landing/assets/anim/idle/frame_04.webp +0 -0
- package/public-landing/assets/anim/idle/frame_05.webp +0 -0
- package/public-landing/assets/anim/idle/frame_06.webp +0 -0
- package/public-landing/assets/anim/idle/frame_07.webp +0 -0
- package/public-landing/assets/anim/idle/frame_08.webp +0 -0
- package/public-landing/assets/anim/idle/frame_09.webp +0 -0
- package/public-landing/assets/anim/idle/frame_10.webp +0 -0
- package/public-landing/assets/anim/idle/frame_11.webp +0 -0
- package/public-landing/assets/anim/idle/frame_12.webp +0 -0
- package/public-landing/assets/anim/idle/frame_13.webp +0 -0
- package/public-landing/assets/anim/idle/frame_14.webp +0 -0
- package/public-landing/assets/anim/idle/frame_15.webp +0 -0
- package/public-landing/assets/anim/idle/frame_16.webp +0 -0
- package/public-landing/assets/anim/idle/frame_17.webp +0 -0
- package/public-landing/assets/anim/idle/frame_18.webp +0 -0
- package/public-landing/assets/anim/idle/frame_19.webp +0 -0
- package/public-landing/assets/anim/idle/frame_20.webp +0 -0
- package/public-landing/assets/anim/idle/frame_21.webp +0 -0
- package/public-landing/assets/anim/idle/frame_22.webp +0 -0
- package/public-landing/assets/anim/idle/frame_23.webp +0 -0
- package/public-landing/assets/anim/idle/frame_24.webp +0 -0
- package/public-landing/assets/anim/idle/frame_25.webp +0 -0
- package/public-landing/assets/anim/idle/frame_26.webp +0 -0
- package/public-landing/assets/anim/idle/frame_27.webp +0 -0
- package/public-landing/assets/anim/idle/frame_28.webp +0 -0
- package/public-landing/assets/anim/idle/frame_29.webp +0 -0
- package/public-landing/assets/anim/idle/frame_30.webp +0 -0
- package/public-landing/assets/anim/idle/frame_31.webp +0 -0
- package/public-landing/assets/anim/idle/frame_32.webp +0 -0
- package/public-landing/assets/anim/idle/frame_33.webp +0 -0
- package/public-landing/assets/anim/idle/frame_34.webp +0 -0
- package/public-landing/assets/anim/idle/frame_35.webp +0 -0
- package/public-landing/assets/anim/idle/frame_36.webp +0 -0
- package/public-landing/assets/anim/idle/frame_37.webp +0 -0
- package/public-landing/assets/anim/idle/frame_38.webp +0 -0
- package/public-landing/assets/anim/idle/frame_39.webp +0 -0
- package/public-landing/assets/anim/idle/frame_40.webp +0 -0
- package/public-landing/assets/anim/idle/frame_41.webp +0 -0
- package/public-landing/assets/anim/idle/frame_42.webp +0 -0
- package/public-landing/assets/anim/idle/frame_43.webp +0 -0
- package/public-landing/create.html +51 -58
- package/public-landing/gate/README.md +137 -0
- package/public-landing/gate/dispmaps/bar.png +0 -0
- package/public-landing/gate/dispmaps/flat.png +0 -0
- package/public-landing/gate/dispmaps/key.png +0 -0
- package/public-landing/gate/index.html +587 -0
- package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
- package/public-landing/gate/previews/off-the-boats.jpg +0 -0
- package/public-landing/gate/space.css +799 -0
- package/public-landing/gate/space.js +1826 -0
- package/public-landing/gate/sprites/enter.png +0 -0
- package/public-landing/gate/sprites/search.png +0 -0
- package/public-landing/gate/sprites/terminal-blank.png +0 -0
- package/public-landing/gate/sprites/tile.png +0 -0
- package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
- package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
- package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
- package/public-landing/world/assets/plates/scene-establishing.png +0 -0
- package/scripts/gds/abandon.js +6 -4
- package/scripts/gds/api.js +10 -5
- package/scripts/gds/api.ps1 +26 -0
- package/scripts/gds/api.sh +6 -0
- package/scripts/gds/audit-ships.js +7 -1
- package/scripts/gds/backfill-sessions.js +78 -18
- package/scripts/gds/backup.js +23 -1
- package/scripts/gds/box-connect-lib.js +124 -31
- package/scripts/gds/box-sync.js +66 -0
- package/scripts/gds/box.js +225 -53
- package/scripts/gds/cf-tunnel.js +145 -6
- package/scripts/gds/claim.js +34 -3
- package/scripts/gds/cli-lib.js +161 -27
- package/scripts/gds/code.js +6 -2
- package/scripts/gds/deploy-divergence.js +209 -0
- package/scripts/gds/dev-lib.js +309 -0
- package/scripts/gds/dev.js +322 -0
- package/scripts/gds/doctor.js +90 -61
- package/scripts/gds/fetch-art-key.js +1 -1
- package/scripts/gds/fetch-sound-prefs.js +2 -2
- package/scripts/gds/fitness.js +228 -12
- package/scripts/gds/gds-db-backup.service +16 -1
- package/scripts/gds/gds-db-offsite.service +9 -1
- package/scripts/gds/gen-api-client.js +1 -1
- package/scripts/gds/gen-api-docs.js +36 -14
- package/scripts/gds/gen-diagrams.js +45 -28
- package/scripts/gds/gen-file-map.js +2 -1
- package/scripts/gds/gen-freshness.js +32 -0
- package/scripts/gds/gen-repo-map.js +3 -2
- package/scripts/gds/gen-session-index.js +14 -5
- package/scripts/gds/hooks/pre-push.js +2 -2
- package/scripts/gds/init.js +60 -3
- package/scripts/gds/install-git-hooks.js +1 -1
- package/scripts/gds/key-card.js +15 -6
- package/scripts/gds/key-status.js +1 -1
- package/scripts/gds/linkify-refs.js +35 -9
- package/scripts/gds/login.js +16 -1
- package/scripts/gds/paste-token.js +7 -1
- package/scripts/gds/preflight.js +126 -0
- package/scripts/gds/provision.js +123 -12
- package/scripts/gds/publish-manifest.js +7 -1
- package/scripts/gds/reauth.js +7 -3
- package/scripts/gds/regen-instance-docs.js +47 -0
- package/scripts/gds/run-unit-tests.js +4 -2
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
- package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
- package/scripts/gds/sequence.js +425 -0
- package/scripts/gds/session-cost.js +10 -1
- package/scripts/gds/setup.js +31 -5
- package/scripts/gds/shell.js +5 -3
- package/scripts/gds/ship.js +319 -29
- package/scripts/gds/smoke-gds.js +139 -8
- package/scripts/gds/start.js +171 -22
- package/scripts/gds/status.js +1 -1
- package/scripts/gds/triage.js +10 -9
- package/scripts/gds/upgrade.js +124 -2
- package/scripts/status-mirror-sync.js +114 -84
- package/src/bongos/api-errors.js +1 -0
- package/src/bongos/auth.js +447 -102
- package/src/bongos/db-kernel.js +27 -0
- package/src/bongos/db.js +39 -0
- package/src/bongos/module-scope-map.js +27 -1
- package/src/bongos/permission-path-check.js +136 -102
- package/src/bongos/repo-info.js +47 -11
- package/src/bongos/route-rank-check.js +429 -46
- package/src/bongos/routes/_helpers.js +12 -1
- package/src/bongos/routes/auth.js +219 -2
- package/src/bongos/routes/backup.js +58 -2
- package/src/bongos/routes/me.js +35 -1
- package/src/bongos/serve-internal.js +84 -15
- package/src/branding.js +32 -0
- package/src/instance-config.js +30 -0
- package/src/module-api.js +112 -1
- package/src/platform-server.js +86 -9
- package/tests/abandon_task.mjs +59 -3
- package/tests/api_cli_flags.mjs +53 -0
- package/tests/auth_page_gate.mjs +13 -0
- package/tests/backfill_sessions.mjs +127 -1
- package/tests/backup_cli.mjs +54 -0
- package/tests/bongos_box_connect.mjs +77 -0
- package/tests/box_access.mjs +130 -1
- package/tests/box_credential.mjs +125 -0
- package/tests/box_host_keys.mjs +24 -0
- package/tests/box_infra_resolve.mjs +149 -0
- package/tests/box_scope_session.mjs +6 -2
- package/tests/box_sync.mjs +55 -0
- package/tests/box_task_scope.mjs +99 -0
- package/tests/branding.mjs +12 -0
- package/tests/cf_ruleset_preflight.mjs +142 -0
- package/tests/cf_tunnel.mjs +37 -0
- package/tests/claim_gate_rebase.mjs +98 -0
- package/tests/clawback_confirmed_backlog.mjs +103 -0
- package/tests/cli_lib_formatters.mjs +20 -0
- package/tests/confirm_attribution.mjs +30 -46
- package/tests/credit_grant.mjs +198 -10
- package/tests/criterion_authoring_gate.mjs +272 -0
- package/tests/criterion_progress.mjs +33 -1
- package/tests/dev_lib.mjs +253 -0
- package/tests/devbox_artifact_gate.mjs +75 -0
- package/tests/devbox_dmg_backdrop.mjs +137 -0
- package/tests/devbox_icons.mjs +304 -0
- package/tests/devbox_installer_brand.mjs +232 -0
- package/tests/devbox_key_register.mjs +234 -0
- package/tests/docs_openapi_route.mjs +110 -0
- package/tests/doctor_hooks.mjs +141 -0
- package/tests/extract_json.mjs +140 -0
- package/tests/fitness.mjs +89 -0
- package/tests/gen_freshness.mjs +96 -0
- package/tests/goal_advisory.mjs +251 -0
- package/tests/goal_criterion_confirm_ui.mjs +269 -0
- package/tests/goal_routes.mjs +59 -4
- package/tests/goal_tier.mjs +12 -3
- package/tests/governance_catalog.mjs +129 -0
- package/tests/governance_claim_eligibility.mjs +262 -0
- package/tests/governance_config.mjs +187 -0
- package/tests/governance_ownership_scope.mjs +410 -0
- package/tests/governance_page_gates.mjs +324 -0
- package/tests/governance_parity.mjs +336 -0
- package/tests/governance_principals.mjs +232 -0
- package/tests/governance_protected_surfaces.mjs +208 -0
- package/tests/governance_require_permission.mjs +223 -0
- package/tests/governance_resolver.mjs +84 -0
- package/tests/governance_role_sync.mjs +231 -0
- package/tests/governance_seed.mjs +127 -0
- package/tests/governance_session_scope.mjs +434 -0
- package/tests/governance_vanilla_boot.mjs +203 -0
- package/tests/grade_attribution.mjs +7 -7
- package/tests/hall_audit.mjs +223 -0
- package/tests/hall_nav.mjs +191 -0
- package/tests/hall_palette.mjs +206 -0
- package/tests/hall_signout.mjs +124 -0
- package/tests/hook_user_agents.mjs +10 -0
- package/tests/idea_triage.mjs +162 -0
- package/tests/idp_device_exchange.mjs +93 -0
- package/tests/init.mjs +51 -0
- package/tests/instance_config.mjs +65 -0
- package/tests/instance_mismatch_guard.mjs +23 -6
- package/tests/instance_release_config.mjs +104 -0
- package/tests/linkify_refs.mjs +15 -2
- package/tests/module_contributions.mjs +55 -0
- package/tests/module_loader.mjs +10 -5
- package/tests/module_scope_active_claims.mjs +94 -0
- package/tests/needs_rebase.mjs +92 -0
- package/tests/one_active_claim_per_session.mjs +76 -0
- package/tests/override_attribution.mjs +10 -8
- package/tests/override_request_ownership.mjs +8 -4
- package/tests/parse_cookie_decode.mjs +42 -0
- package/tests/pay_on_land.mjs +129 -0
- package/tests/platform_boot.mjs +100 -1
- package/tests/post_login_landing.mjs +42 -0
- package/tests/preflight_checks.mjs +72 -0
- package/tests/provision.mjs +132 -7
- package/tests/publish_branch_route.mjs +53 -0
- package/tests/publish_reconciler.mjs +187 -2
- package/tests/repo_info_binding.mjs +248 -0
- package/tests/reward_gate.mjs +11 -2
- package/tests/reward_mode_cost_plus_only.mjs +116 -0
- package/tests/reward_mode_surfacing.mjs +168 -0
- package/tests/route_permission_check.mjs +301 -0
- package/tests/route_rank_check.mjs +254 -12
- package/tests/route_validation.mjs +30 -0
- package/tests/sequence.mjs +267 -0
- package/tests/session_digest.mjs +44 -0
- package/tests/session_index.mjs +18 -6
- package/tests/session_records.mjs +39 -1
- package/tests/session_reward_on_land.mjs +381 -0
- package/tests/session_reward_reconcile.mjs +229 -0
- package/tests/ship_api_client_pathspec.mjs +100 -0
- package/tests/ship_base_flag.mjs +93 -0
- package/tests/ship_ci_deploy.mjs +80 -3
- package/tests/ship_upstream_deletion.mjs +57 -0
- package/tests/smoke_target.mjs +233 -0
- package/tests/start_env_guard.mjs +87 -0
- package/tests/start_rebase_warning.mjs +103 -0
- package/tests/status_mirror_sync.mjs +122 -0
- package/tests/stop_refcheck.mjs +19 -1
- package/tests/task_goal_link.mjs +15 -6
- package/tests/upgrade.mjs +139 -0
- package/tests/web_admission_status.mjs +162 -0
- package/tests/write_validation_gaps.mjs +110 -0
|
@@ -133,11 +133,31 @@ a.goal-card:hover { text-decoration: none; border-color: var(--border-strong); b
|
|
|
133
133
|
.conflict__sev--medium { background: var(--warn-weak); color: var(--warn); }
|
|
134
134
|
|
|
135
135
|
.crit-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; }
|
|
136
|
-
|
|
136
|
+
/* task 1002164 — a third trailing column holds the per-criterion Confirm action;
|
|
137
|
+
it collapses to zero width on the rows that have none. */
|
|
138
|
+
.crit { display: grid; grid-template-columns: 22px minmax(0,1fr) auto; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--rule-soft); font-size: 13px; }
|
|
137
139
|
.crit:last-child { border-bottom: none; }
|
|
138
140
|
.crit__mark { width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid var(--border-strong); display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--ink-faint); }
|
|
139
141
|
.crit--done .crit__mark { background: var(--ok); border-color: var(--ok); color: #fff; }
|
|
140
142
|
.crit--done .crit__text { color: var(--ink-soft); }
|
|
143
|
+
|
|
144
|
+
/* task 1002164 — "met, awaiting confirmation": every linked task shipped but the
|
|
145
|
+
criterion is not yet confirmed. Distinct from both done (solid ✓) and open
|
|
146
|
+
(empty circle) so the three states read apart at a glance. */
|
|
147
|
+
.crit--pending .crit__mark { border-color: var(--warn); color: var(--warn); font-weight: 700; }
|
|
148
|
+
.crit__act { display: flex; align-items: center; }
|
|
149
|
+
.crit-list--full .crit__act { align-self: start; padding-top: 1px; }
|
|
150
|
+
.crit__confirm {
|
|
151
|
+
cursor: pointer; white-space: nowrap; padding: 3px 10px; border-radius: 999px;
|
|
152
|
+
border: 1px solid var(--ok); background: transparent; color: var(--ok);
|
|
153
|
+
font: inherit; font-size: 11.5px; font-weight: 600;
|
|
154
|
+
}
|
|
155
|
+
.crit__confirm:hover:not(:disabled) { background: var(--ok); color: #fff; }
|
|
156
|
+
.crit__confirm:disabled { opacity: .6; cursor: default; }
|
|
157
|
+
.crit__flag {
|
|
158
|
+
white-space: nowrap; padding: 2px 8px; border-radius: 999px;
|
|
159
|
+
background: var(--warn-weak); color: var(--warn); font-size: 10.5px; font-weight: 600;
|
|
160
|
+
}
|
|
141
161
|
/* BV1.R79: per-criterion expand in the capped band — short label, full text on
|
|
142
162
|
click (matches the Roadmap page's .vbar__crit-d pattern). */
|
|
143
163
|
.crit-d { min-width: 0; }
|
|
@@ -181,3 +201,61 @@ a.goal-card:hover { text-decoration: none; border-color: var(--border-strong); b
|
|
|
181
201
|
|
|
182
202
|
/* Filtered-count line under the kit filter bar (list view). */
|
|
183
203
|
.goals-count-line { margin: -4px 0 12px; font-size: 12.5px; color: var(--ink-faint); }
|
|
204
|
+
|
|
205
|
+
/* ============================================================
|
|
206
|
+
task 1002439 — Goals "what's next" rollup (grouped list view).
|
|
207
|
+
Replaces the paginated card grid: a task-readiness summary, then
|
|
208
|
+
goals grouped Active / Blocked / Achieved. Each row rolls its
|
|
209
|
+
tasks up into ready/in-progress/blocked; the task→task dependency
|
|
210
|
+
graph itself lives on the Tasks page. Uses the shared style.css tokens.
|
|
211
|
+
============================================================ */
|
|
212
|
+
/* The list container used to be an auto-fill CARD grid; the rollup renders
|
|
213
|
+
grouped full-width blocks into it, so flip it to normal block flow. */
|
|
214
|
+
#goal-grid.goal-grid { display: block; gap: 0; }
|
|
215
|
+
.gr-summary { display: flex; flex-wrap: wrap; gap: 22px; margin: 6px 0 20px; }
|
|
216
|
+
.gr-sm { display: flex; align-items: baseline; gap: 8px; font-size: 13px; color: var(--ink-soft); }
|
|
217
|
+
.gr-sm b { font-size: 20px; font-weight: 700; letter-spacing: -.02em; color: var(--ink); font-variant-numeric: tabular-nums; }
|
|
218
|
+
.gr-sm__dot { width: 8px; height: 8px; border-radius: 50%; align-self: center; }
|
|
219
|
+
|
|
220
|
+
.gr-sec { display: flex; align-items: center; gap: 9px; margin: 26px 0 8px; }
|
|
221
|
+
.gr-sec b { font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-faint); }
|
|
222
|
+
.gr-sec__n { font-size: 12px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
223
|
+
|
|
224
|
+
.gr-list { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card); overflow: hidden; }
|
|
225
|
+
.gr-row { display: grid; grid-template-columns: auto 1fr auto; gap: 16px; align-items: center; padding: 15px 17px; border-bottom: 1px solid var(--rule-soft); }
|
|
226
|
+
.gr-row:last-child { border-bottom: 0; }
|
|
227
|
+
.gr-row:hover { background: color-mix(in srgb, var(--ink) 2.5%, var(--bg-card)); }
|
|
228
|
+
.gr-ringcol { flex: none; }
|
|
229
|
+
.gr-crit-none { display: inline-grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; border: 2px solid var(--rule); color: var(--ink-faint); font-size: 13px; }
|
|
230
|
+
.gr-main { min-width: 0; }
|
|
231
|
+
.gr-title { display: inline-block; font-size: 15px; font-weight: 650; letter-spacing: -.01em; color: var(--ink); line-height: 1.3; }
|
|
232
|
+
.gr-title:hover { color: var(--accent-text); }
|
|
233
|
+
.gr-meta { font-size: 12px; color: var(--ink-faint); margin-top: 3px; font-variant-numeric: tabular-nums; }
|
|
234
|
+
.gr-roll { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 8px; }
|
|
235
|
+
.gr-d { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
|
|
236
|
+
.gr-d i { width: 7px; height: 7px; border-radius: 50%; }
|
|
237
|
+
.gr-d b { color: var(--ink); font-weight: 600; }
|
|
238
|
+
.gr-right { text-align: right; min-width: 150px; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
|
|
239
|
+
.gr-next { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; max-width: 230px; }
|
|
240
|
+
.gr-next__t { font-size: 12.5px; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 230px; }
|
|
241
|
+
.gr-claim { background: var(--accent); color: #fff; border-radius: 8px; padding: 6px 14px; font-size: 12.5px; font-weight: 650; white-space: nowrap; }
|
|
242
|
+
.gr-claim:hover { background: var(--accent-deep); }
|
|
243
|
+
.gr-drill { font-size: 12.5px; color: var(--ink-faint); display: inline-flex; align-items: center; gap: 5px; }
|
|
244
|
+
.gr-drill:hover { color: var(--accent-text); }
|
|
245
|
+
.gr-met { font-size: 12.5px; font-weight: 600; color: var(--ok); }
|
|
246
|
+
.gr-quiet { font-size: 12.5px; color: var(--ink-faint); }
|
|
247
|
+
|
|
248
|
+
.gr-pills { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
249
|
+
.gr-pill { display: inline-flex; align-items: center; gap: 8px; background: var(--bg-card); border: 1px solid var(--rule); border-radius: 20px; padding: 6px 13px 6px 8px; color: var(--ink-soft); font-size: 12.5px; }
|
|
250
|
+
.gr-pill:hover { border-color: var(--border-strong); }
|
|
251
|
+
.gr-pill b { color: var(--ink); font-weight: 600; }
|
|
252
|
+
.gr-pill__ok { width: 17px; height: 17px; border-radius: 50%; background: var(--ok-weak); color: var(--ok); display: grid; place-items: center; font-size: 10px; font-weight: 800; }
|
|
253
|
+
.gr-pill__id { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
254
|
+
.gr-pills--muted { opacity: .6; }
|
|
255
|
+
|
|
256
|
+
@media (max-width: 640px) {
|
|
257
|
+
.gr-row { grid-template-columns: auto 1fr; row-gap: 11px; }
|
|
258
|
+
.gr-right { grid-column: 1 / -1; align-items: flex-start; text-align: left; }
|
|
259
|
+
.gr-next { align-items: flex-start; }
|
|
260
|
+
.gr-next__t { max-width: 100%; }
|
|
261
|
+
}
|
|
@@ -14,6 +14,14 @@
|
|
|
14
14
|
block per the hall placement rules; shared pager/filter/tab/count-pill
|
|
15
15
|
styles now live in style.css's hall-kit section. -->
|
|
16
16
|
<link rel="stylesheet" href="/builders/goals.css">
|
|
17
|
+
<!-- task 1002425 — the goal-detail "Tasks" pane mirrors the Tasks board's
|
|
18
|
+
claimable cards + bulk toolbar, so it needs the board's page-local card /
|
|
19
|
+
.task__claim / .bulk-toolbar styling. That styling lives in work.css (the
|
|
20
|
+
shared base .task grid is already in style.css above); linking it here is
|
|
21
|
+
the no-duplication way to give both surfaces identical cards. (Follow-up:
|
|
22
|
+
promote the shared card/toolbar rules into style.css so work.css can go
|
|
23
|
+
back to being board-only — idea captured at ship.) -->
|
|
24
|
+
<link rel="stylesheet" href="/builders/work.css">
|
|
17
25
|
</head>
|
|
18
26
|
<body data-page="goals" data-page-title="Goals">
|
|
19
27
|
|
|
@@ -89,23 +97,25 @@
|
|
|
89
97
|
|
|
90
98
|
<div class="scroll" style="margin-top:20px">
|
|
91
99
|
<div class="goal-work__head">
|
|
92
|
-
<h2 class="scroll__h">
|
|
100
|
+
<h2 class="scroll__h">Tasks</h2>
|
|
93
101
|
<!-- task 2171: the To do / Completed toggle is built by
|
|
94
102
|
OTBKit.makeTabs (hash:false — the #/goal/N sub-route
|
|
95
103
|
namespace stays untouched; tabs key off in-page state). -->
|
|
96
104
|
<div class="goal-work__tabs" id="goal-work-tabs" aria-label="Goal tasks"></div>
|
|
97
105
|
</div>
|
|
98
106
|
<div id="goal-todo-pane" role="tabpanel" aria-labelledby="tab-todo">
|
|
99
|
-
<!-- task
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<
|
|
107
|
+
<!-- task 1002425 — the To-do pane mirrors the Tasks board's Ready
|
|
108
|
+
queue so a goal's tasks have the same functionality as the board:
|
|
109
|
+
a shared filter bar → rich claimable cards → multi-select with
|
|
110
|
+
bulk claim → per-card copy-prompt, all opening the same task
|
|
111
|
+
overlay. Scoped to this goal, so no Version/Goal filters (they'd
|
|
112
|
+
be redundant). Sorting moved from the old column headers onto the
|
|
113
|
+
filter bar's Sort control (matching the board). -->
|
|
114
|
+
<div id="goal-work-filters"></div>
|
|
115
|
+
<p class="claim-count-line" id="goal-todo-count" aria-live="polite"></p>
|
|
116
|
+
<div class="task-list" id="goal-todo-list">
|
|
117
|
+
<div class="profile__placeholder">…</div>
|
|
118
|
+
</div>
|
|
109
119
|
<div id="goal-todo-pager-mount"></div>
|
|
110
120
|
</div>
|
|
111
121
|
<div id="goal-done-pane" role="tabpanel" aria-labelledby="tab-done" hidden>
|
|
@@ -119,6 +129,21 @@
|
|
|
119
129
|
<div id="goal-done-pager-mount"></div>
|
|
120
130
|
</div>
|
|
121
131
|
</div>
|
|
132
|
+
|
|
133
|
+
<!-- task 1002425 — bulk-action toolbar for the goal's task cards,
|
|
134
|
+
mirroring the Tasks board's toolbar. Hidden until 1+ ready cards are
|
|
135
|
+
selected. position:fixed (via .bulk-toolbar in work.css) so its DOM
|
|
136
|
+
location here is immaterial; it lives inside the detail view so it's
|
|
137
|
+
scoped to this route and cleared on route change. Bulk claim is the
|
|
138
|
+
headline action; bulk release + copy parallel/sequential prompts
|
|
139
|
+
stay board-only for now (noted follow-up). -->
|
|
140
|
+
<div id="goal-bulk-toolbar" class="bulk-toolbar" hidden role="region" aria-label="Bulk actions">
|
|
141
|
+
<span class="bulk-toolbar__count" id="goal-bulk-count"></span>
|
|
142
|
+
<div class="bulk-toolbar__actions">
|
|
143
|
+
<button type="button" class="bulk-toolbar__btn" id="goal-bulk-claim-btn">Bulk claim</button>
|
|
144
|
+
</div>
|
|
145
|
+
<button type="button" class="bulk-toolbar__clear" id="goal-bulk-clear-btn">Clear</button>
|
|
146
|
+
</div>
|
|
122
147
|
</section>
|
|
123
148
|
|
|
124
149
|
<!-- CONFLICTS full view (hash-routed: #/goal/N/conflicts) — the whole
|
|
@@ -164,6 +189,8 @@
|
|
|
164
189
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
165
190
|
|
|
166
191
|
<script src="/builders/shell.js?v=2026-07-03-goals1"></script>
|
|
192
|
+
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
193
|
+
<script src="/builders/palette.js" defer></script>
|
|
167
194
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
168
195
|
<!-- shared component kit (window.OTBKit) — pager, filter bar, tabs, empty/skeleton (task 2166). -->
|
|
169
196
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -3,13 +3,21 @@
|
|
|
3
3
|
// Every widget — core here, module-contributed from a module's own client script —
|
|
4
4
|
// registers into the window.OTB hall-widget registry (dom-utils.js), and builders.js
|
|
5
5
|
// mounts the registered set into the shell's view containers (task 1723 redesign):
|
|
6
|
-
// view:
|
|
7
|
-
// zone:
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// view: 'home' | 'standing' | 'leaderboard' (default 'home')
|
|
7
|
+
// zone: a finer mount target inside the Home view
|
|
8
|
+
// ('home-banner' | 'home-stats' | 'home-band' | 'home-main')
|
|
9
|
+
// group: a finer mount target inside Standing — which rail section this card
|
|
10
|
+
// belongs to ('work' | 'karma' | 'progress' | 'achievements', task 2174).
|
|
11
|
+
// All three ride the registry entry untouched; builders.js resolves them to the
|
|
12
|
+
// #zone-*/#standing-* containers and falls back to <main> when absent, so a
|
|
11
13
|
// module widget written before the redesign still lands (on Home).
|
|
12
14
|
//
|
|
15
|
+
// task 2174 — Standing is "one identity band, then rail-navigated sections grouped
|
|
16
|
+
// by question": the Profile card is the band, and every other Standing widget
|
|
17
|
+
// declares the `group` that answers its question. Achievements folded in from the
|
|
18
|
+
// retired #achievements hash view; the security-bounty rate card moved off Standing
|
|
19
|
+
// to /drachmae (a reward schedule is reference material, not personal standing).
|
|
20
|
+
//
|
|
13
21
|
// Each widget owns its skeleton markup. mount(host) stamps that skeleton into the
|
|
14
22
|
// registry-made <section>; builders.js then wires data to the same element ids it
|
|
15
23
|
// always has (#profile-body, #recent-ships, …) — the data-rendering code is
|
|
@@ -27,9 +35,13 @@
|
|
|
27
35
|
// setHtml — stamp a widget's skeleton into its host <section>. The host element
|
|
28
36
|
// already carries the section's stable id + class (builders.js creates it from the
|
|
29
37
|
// registry entry), so the skeleton is just the inner content.
|
|
38
|
+
// task 2177: `core: true` marks these as the hall's OWN cards, which exempts a
|
|
39
|
+
// home-main one from the summary/collapsed rule contributeHallWidget applies to
|
|
40
|
+
// everything else. It is a statement about provenance, not a privilege to grow —
|
|
41
|
+
// the zone budgets in builders.js still bind, and CI asserts them.
|
|
30
42
|
const w = (id, label, order, html, opts) =>
|
|
31
43
|
reg(Object.assign({
|
|
32
|
-
id, label, order,
|
|
44
|
+
id, label, order, core: true,
|
|
33
45
|
mount(host) { host.innerHTML = html; },
|
|
34
46
|
}, opts || {}));
|
|
35
47
|
|
|
@@ -100,12 +112,15 @@
|
|
|
100
112
|
|
|
101
113
|
/* ---------------- Standing ---------------- */
|
|
102
114
|
|
|
103
|
-
// 1. Profile — the identity band at the top of Standing (#726).
|
|
115
|
+
// 1. Profile — the identity band at the top of Standing (#726). No `group`:
|
|
116
|
+
// the band sits above the rail sections and is never a rail entry.
|
|
104
117
|
w('profile-scroll', 'Profile', 20,
|
|
105
118
|
'<h2 id="profile-h" class="sr-only">Profile</h2>' +
|
|
106
119
|
'<div class="profile" id="profile-body"><div class="profile__placeholder">…</div></div>',
|
|
107
120
|
{ view: 'standing', sectionClass: 'scroll scroll--profile', labelledby: 'profile-h' });
|
|
108
121
|
|
|
122
|
+
/* -- Work — "what have I shipped, and how was it judged" -- */
|
|
123
|
+
|
|
109
124
|
// 2. WORKS — recent ships.
|
|
110
125
|
w('ships-scroll', 'Your work', 30,
|
|
111
126
|
'<h2 id="ships-h" class="scroll__h">Your work</h2>' +
|
|
@@ -124,66 +139,64 @@
|
|
|
124
139
|
'</div>' +
|
|
125
140
|
'<table class="ledger" id="recent-ships"><thead><tr><th>№</th><th>Work</th><th data-currency-label="caps">Credits</th><th>Shipped</th></tr></thead>' +
|
|
126
141
|
'<tbody><tr><td colspan="4" class="ledger__empty">…</td></tr></tbody></table>' +
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
'</div>',
|
|
132
|
-
{ view: 'standing', labelledby: 'ships-h' });
|
|
142
|
+
// task 2174: the hand-rolled prev/next bar gives way to the OTBKit pager
|
|
143
|
+
// (per-page select, page indicator, clamping) — same #ships-* id prefix.
|
|
144
|
+
window.OTBKit.pagerBarHtml('ships', { label: 'shipped work' }),
|
|
145
|
+
{ view: 'standing', group: 'work', labelledby: 'ships-h' });
|
|
133
146
|
|
|
134
|
-
// 3.
|
|
135
|
-
w('
|
|
136
|
-
'<h2 id="curve-h" class="scroll__h">Progress</h2>' +
|
|
137
|
-
'<p class="scroll__lede">How your output has changed over time — work shipped, cost and time per work, and how reviews held up. <span id="curve-scope-note"></span></p>' +
|
|
138
|
-
'<div class="curve" id="curve-body">' +
|
|
139
|
-
'<div class="profile__placeholder" id="curve-empty" style="display:none;">Not enough shipped work yet to chart.</div>' +
|
|
140
|
-
'<div class="curve__headline" id="curve-headline"></div>' +
|
|
141
|
-
'<div class="curve__grid" id="curve-grid"></div>' +
|
|
142
|
-
'<div class="curve__kinds" id="curve-kinds"></div>' +
|
|
143
|
-
'</div>',
|
|
144
|
-
{ view: 'standing', labelledby: 'curve-h', hiddenByDefault: true });
|
|
145
|
-
|
|
146
|
-
// 4. MARKS — review quality of recent output.
|
|
147
|
-
w('grades-scroll', 'Reviews', 50,
|
|
147
|
+
// 3. MARKS — review quality of recent output.
|
|
148
|
+
w('grades-scroll', 'Reviews', 32,
|
|
148
149
|
'<h2 id="marks-h" class="scroll__h">Reviews</h2>' +
|
|
149
150
|
'<div class="profile__placeholder" id="marks-empty" style="display:none;">No work reviewed yet.</div>' +
|
|
150
151
|
'<table class="ledger" id="recent-grades"><thead><tr><th>№</th><th>Work</th><th>Score</th><th>Verdict</th><th>Reviewed</th></tr></thead>' +
|
|
151
152
|
'<tbody><tr><td colspan="5" class="ledger__empty">…</td></tr></tbody></table>' +
|
|
152
153
|
'<p class="ledger__note" id="grades-rolling-note" hidden></p>',
|
|
153
|
-
{ view: 'standing', labelledby: 'marks-h' });
|
|
154
|
+
{ view: 'standing', group: 'work', labelledby: 'marks-h' });
|
|
155
|
+
|
|
156
|
+
/* -- Karma — peer standing; one currency, one section -- */
|
|
154
157
|
|
|
155
|
-
//
|
|
156
|
-
w('karma-scroll', 'Karma',
|
|
158
|
+
// 4. KARMA feed — V3.R26 (#246). Hidden until /me returns karma data.
|
|
159
|
+
w('karma-scroll', 'Karma', 40,
|
|
157
160
|
'<h2 id="karma-h" class="scroll__h">Karma</h2>' +
|
|
158
161
|
'<p class="scroll__lede">Karma rewards good citizenship — ratified ideas, peer recognition, approvals. Distinct from ' + curLabel() + ', which counts work shipped.</p>' +
|
|
159
162
|
'<table class="ledger" id="karma-feed"><thead><tr><th>When</th><th>Delta</th><th>Reason</th><th>Granted by</th></tr></thead>' +
|
|
160
163
|
'<tbody><tr><td colspan="4" class="ledger__empty">…</td></tr></tbody></table>',
|
|
161
|
-
{ view: 'standing', labelledby: 'karma-h', hiddenByDefault: true });
|
|
164
|
+
{ view: 'standing', group: 'karma', labelledby: 'karma-h', hiddenByDefault: true });
|
|
162
165
|
|
|
163
|
-
//
|
|
164
|
-
w('acclaim-scroll', 'Peer recognition',
|
|
166
|
+
// 4b. Peer acclaim — V3.R25 (#245). Hidden until data.
|
|
167
|
+
w('acclaim-scroll', 'Peer recognition', 42,
|
|
165
168
|
'<h2 id="acclaim-h" class="scroll__h">Peer recognition</h2>' +
|
|
166
169
|
'<p class="scroll__lede">Recognize your peers’ finished work. A vote up (+) or down (−) shapes their karma after a one-week cooling period. You can’t vote on your own work.</p>' +
|
|
167
170
|
'<table class="ledger" id="acclaim-feed"><thead><tr><th>Work</th><th>By</th><th>Votes</th><th>Your vote</th></tr></thead>' +
|
|
168
|
-
'<tbody><tr><td colspan="4" class="ledger__empty">…</td></tr></tbody></table>'
|
|
169
|
-
|
|
171
|
+
'<tbody><tr><td colspan="4" class="ledger__empty">…</td></tr></tbody></table>' +
|
|
172
|
+
// task 1002446: the last unpaged list in the hall. The feed is already
|
|
173
|
+
// client-side, so the kit's pager fits without touching the endpoint.
|
|
174
|
+
window.OTBKit.pagerBarHtml('acclaim', { label: 'entries' }),
|
|
175
|
+
{ view: 'standing', group: 'karma', labelledby: 'acclaim-h', hiddenByDefault: true });
|
|
176
|
+
|
|
177
|
+
/* -- Progress — how the output has changed over time -- */
|
|
170
178
|
|
|
171
|
-
//
|
|
172
|
-
w('
|
|
173
|
-
'<h2 id="
|
|
174
|
-
'<p class="scroll__lede">
|
|
175
|
-
'<
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
// 5. CURVE — the builder's development curve (V3.R72 #291, C5).
|
|
180
|
+
w('analytics-scroll', 'Progress', 50,
|
|
181
|
+
'<h2 id="curve-h" class="scroll__h">Progress</h2>' +
|
|
182
|
+
'<p class="scroll__lede">How your output has changed over time — work shipped, cost and time per work, and how reviews held up. <span id="curve-scope-note"></span></p>' +
|
|
183
|
+
'<div class="curve" id="curve-body">' +
|
|
184
|
+
'<div class="profile__placeholder" id="curve-empty" style="display:none;">Not enough shipped work yet to chart.</div>' +
|
|
185
|
+
'<div class="curve__headline" id="curve-headline"></div>' +
|
|
186
|
+
'<div class="curve__grid" id="curve-grid"></div>' +
|
|
187
|
+
'<div class="curve__kinds" id="curve-kinds"></div>' +
|
|
188
|
+
'</div>',
|
|
189
|
+
{ view: 'standing', group: 'progress', labelledby: 'curve-h', hiddenByDefault: true });
|
|
178
190
|
|
|
179
|
-
/*
|
|
191
|
+
/* -- Achievements — long-term progression (folded in from the retired
|
|
192
|
+
#achievements hash view, task 2174) -- */
|
|
180
193
|
|
|
181
|
-
//
|
|
182
|
-
w('honours-scroll', 'Achievements',
|
|
183
|
-
'<h2 id="ach-h" class="
|
|
194
|
+
// 6. Achievements (#726).
|
|
195
|
+
w('honours-scroll', 'Achievements', 60,
|
|
196
|
+
'<h2 id="ach-h" class="scroll__h">Achievements</h2>' +
|
|
184
197
|
'<p class="scroll__lede">Eight achievements recognize sustained contribution. Earned ones are highlighted; the rest show what’s left to do.</p>' +
|
|
185
198
|
'<div class="ach-grid" id="ach-grid"><div class="profile__placeholder">…</div></div>',
|
|
186
|
-
{ view: '
|
|
199
|
+
{ view: 'standing', group: 'achievements', labelledby: 'ach-h' });
|
|
187
200
|
|
|
188
201
|
/* ---------------- Leaderboard ---------------- */
|
|
189
202
|
|
|
@@ -197,10 +210,7 @@
|
|
|
197
210
|
'<th class="ledger__sortable" id="lb-sort-karma" aria-sort="none" title="Sort by karma (peer recognition + approvals)">Karma</th>' +
|
|
198
211
|
'<th class="ledger__sortable" id="lb-sort-tokens" aria-sort="none" title="Sort by tokens used across recorded sessions — efficiency is tokens ÷ credits (hover a row for tokens-per-drachma)">Tokens</th>' +
|
|
199
212
|
'</tr></thead><tbody><tr><td colspan="6" class="ledger__empty">…</td></tr></tbody></table>' +
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
'<span id="lb-range" class="pager__range">1–10</span>' +
|
|
203
|
-
'<button class="btn-ghost" id="lb-next">later →</button>' +
|
|
204
|
-
'</div>',
|
|
213
|
+
// task 2174: OTBKit pager — same #lb-* id prefix as the bar it replaces.
|
|
214
|
+
window.OTBKit.pagerBarHtml('lb', { label: 'builders' }),
|
|
205
215
|
{ view: 'leaderboard', labelledby: 'lb-h' });
|
|
206
216
|
})();
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* harbor.css — Page-local styles for the Harbor page (Archon-only).
|
|
2
|
+
Lifted verbatim out of the page's inline <style> block (task 1002176);
|
|
3
|
+
the ?v= cache-bust is stamped automatically from this file's content hash
|
|
4
|
+
at boot (src/asset-version.js). */
|
|
5
|
+
|
|
6
|
+
/* Page-local styles for the harbor — built on the shared design system's
|
|
7
|
+
derived tokens only (no page-local colour values). Each builder's dev
|
|
8
|
+
box renders as a card whose top strip + pill carry its lifecycle state. */
|
|
9
|
+
.harbor-summary {
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
12
|
+
gap: 14px;
|
|
13
|
+
margin: 6px 0 22px;
|
|
14
|
+
}
|
|
15
|
+
.harbor-stat {
|
|
16
|
+
border: 1px solid var(--border);
|
|
17
|
+
border-radius: var(--radius);
|
|
18
|
+
background: var(--surface);
|
|
19
|
+
padding: 12px 14px;
|
|
20
|
+
}
|
|
21
|
+
.harbor-stat__label {
|
|
22
|
+
font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
|
|
23
|
+
font-weight: 600; color: var(--ink-faint);
|
|
24
|
+
}
|
|
25
|
+
.harbor-stat__value {
|
|
26
|
+
font-size: 22px; font-weight: 650; color: var(--ink);
|
|
27
|
+
font-variant-numeric: tabular-nums; margin-top: 2px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* The dock — the strip the box cards sit on. */
|
|
31
|
+
.harbor-dock {
|
|
32
|
+
display: grid;
|
|
33
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
34
|
+
gap: 16px;
|
|
35
|
+
padding: 18px;
|
|
36
|
+
border-radius: var(--radius);
|
|
37
|
+
border: 1px solid var(--border);
|
|
38
|
+
background: var(--surface-2);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.harbor-container {
|
|
42
|
+
border: 1px solid var(--border);
|
|
43
|
+
border-radius: var(--radius);
|
|
44
|
+
background: var(--surface);
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
display: flex; flex-direction: column;
|
|
47
|
+
}
|
|
48
|
+
/* The state strip along the card's top, coloured by lifecycle state. */
|
|
49
|
+
.harbor-container__roof {
|
|
50
|
+
height: 4px;
|
|
51
|
+
background-color: var(--ok);
|
|
52
|
+
}
|
|
53
|
+
.harbor-container--parked .harbor-container__roof { background-color: var(--ink-faint); }
|
|
54
|
+
.harbor-container--pending .harbor-container__roof { background-color: var(--warn); }
|
|
55
|
+
.harbor-container--gone .harbor-container__roof { background-color: var(--border-strong); }
|
|
56
|
+
.harbor-container--error .harbor-container__roof { background-color: var(--danger); }
|
|
57
|
+
.harbor-container--blocked .harbor-container__roof { background-color: var(--danger); }
|
|
58
|
+
|
|
59
|
+
.harbor-container__body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
|
|
60
|
+
.harbor-container__head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
61
|
+
.harbor-container__who { color: var(--ink); font-weight: 600; font-size: 14.5px; }
|
|
62
|
+
.harbor-container__rank { color: var(--ink-faint); font-size: 12px; margin-left: 6px; font-weight: 400; }
|
|
63
|
+
|
|
64
|
+
.harbor-pill {
|
|
65
|
+
font-size: 11px; font-weight: 600;
|
|
66
|
+
letter-spacing: 0.04em; text-transform: uppercase;
|
|
67
|
+
padding: 2px 9px; border-radius: 999px; white-space: nowrap;
|
|
68
|
+
border: 1px solid var(--border); color: var(--ink-soft); background: var(--surface-2);
|
|
69
|
+
}
|
|
70
|
+
.harbor-pill--active { background: var(--ok-weak); border-color: color-mix(in srgb, var(--ok) 30%, transparent); color: var(--ok); }
|
|
71
|
+
.harbor-pill--pending { background: var(--warn-weak); border-color: color-mix(in srgb, var(--warn) 30%, transparent); color: var(--warn); }
|
|
72
|
+
.harbor-pill--blocked { background: var(--danger-weak); border-color: color-mix(in srgb, var(--danger) 30%, transparent); color: var(--danger); }
|
|
73
|
+
|
|
74
|
+
.harbor-rows { list-style: none; padding: 0; margin: 2px 0 0; }
|
|
75
|
+
.harbor-rows li {
|
|
76
|
+
display: flex; justify-content: space-between; gap: 12px;
|
|
77
|
+
padding: 4px 0; border-bottom: 1px solid var(--border);
|
|
78
|
+
font-size: 13px;
|
|
79
|
+
}
|
|
80
|
+
.harbor-rows li:last-child { border-bottom: none; }
|
|
81
|
+
.harbor-rows li .k { color: var(--ink-soft); }
|
|
82
|
+
.harbor-rows li .v { color: var(--ink); font-variant-numeric: tabular-nums; text-align: right; }
|
|
83
|
+
|
|
84
|
+
.harbor-blocked-note {
|
|
85
|
+
font-size: 12.5px; color: var(--danger);
|
|
86
|
+
border-left: 2px solid var(--danger); padding-left: 8px; margin: 2px 0 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.harbor-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 8px; }
|
|
90
|
+
.harbor-btn {
|
|
91
|
+
font: inherit; font-size: 12.5px; font-weight: 500;
|
|
92
|
+
padding: 5px 12px; border: 1px solid var(--border-strong);
|
|
93
|
+
background: var(--surface); color: var(--ink-soft);
|
|
94
|
+
border-radius: var(--radius-sm); cursor: pointer; flex: 1;
|
|
95
|
+
}
|
|
96
|
+
.harbor-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
|
|
97
|
+
.harbor-btn:disabled { opacity: 0.45; cursor: default; }
|
|
98
|
+
.harbor-btn--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
99
|
+
|
|
100
|
+
.harbor-empty, .harbor-sealed { color: var(--ink-soft); padding: 16px 0; }
|
|
101
|
+
|
|
102
|
+
/* Lightweight modal for confirm / block dialogs. Viewport-fixed overlay;
|
|
103
|
+
z-index sits above the shell's sidebar/drawer layers. */
|
|
104
|
+
.harbor-modal-bg {
|
|
105
|
+
position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 45%, transparent);
|
|
106
|
+
display: flex; align-items: center; justify-content: center; z-index: 200; padding: 20px;
|
|
107
|
+
}
|
|
108
|
+
.harbor-modal {
|
|
109
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
|
110
|
+
max-width: 460px; width: 100%; padding: 20px 22px;
|
|
111
|
+
box-shadow: var(--shadow-pop);
|
|
112
|
+
}
|
|
113
|
+
.harbor-modal h2 { color: var(--ink); margin: 0 0 8px; font-size: 16px; font-weight: 650; }
|
|
114
|
+
.harbor-modal p { color: var(--ink); font-size: 13.5px; margin: 0 0 12px; }
|
|
115
|
+
.harbor-modal label { display: block; font-size: 13px; color: var(--ink-soft); margin: 10px 0 4px; }
|
|
116
|
+
.harbor-modal input[type=text], .harbor-modal textarea {
|
|
117
|
+
width: 100%; box-sizing: border-box; font: inherit; font-size: 13.5px;
|
|
118
|
+
padding: 7px 9px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
|
|
119
|
+
background: var(--surface); color: var(--ink);
|
|
120
|
+
}
|
|
121
|
+
.harbor-modal__check { display: flex; align-items: flex-start; gap: 8px; margin: 12px 0 0; font-size: 13px; color: var(--ink); }
|
|
122
|
+
.harbor-modal__check input { margin-top: 3px; }
|
|
123
|
+
.harbor-modal__actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
|
|
@@ -10,126 +10,7 @@
|
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
12
12
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
13
|
-
<
|
|
14
|
-
/* Page-local styles for the harbor — built on the shared design system's
|
|
15
|
-
derived tokens only (no page-local colour values). Each builder's dev
|
|
16
|
-
box renders as a card whose top strip + pill carry its lifecycle state. */
|
|
17
|
-
.harbor-summary {
|
|
18
|
-
display: grid;
|
|
19
|
-
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
20
|
-
gap: 14px;
|
|
21
|
-
margin: 6px 0 22px;
|
|
22
|
-
}
|
|
23
|
-
.harbor-stat {
|
|
24
|
-
border: 1px solid var(--border);
|
|
25
|
-
border-radius: var(--radius);
|
|
26
|
-
background: var(--surface);
|
|
27
|
-
padding: 12px 14px;
|
|
28
|
-
}
|
|
29
|
-
.harbor-stat__label {
|
|
30
|
-
font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
|
|
31
|
-
font-weight: 600; color: var(--ink-faint);
|
|
32
|
-
}
|
|
33
|
-
.harbor-stat__value {
|
|
34
|
-
font-size: 22px; font-weight: 650; color: var(--ink);
|
|
35
|
-
font-variant-numeric: tabular-nums; margin-top: 2px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/* The dock — the strip the box cards sit on. */
|
|
39
|
-
.harbor-dock {
|
|
40
|
-
display: grid;
|
|
41
|
-
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
42
|
-
gap: 16px;
|
|
43
|
-
padding: 18px;
|
|
44
|
-
border-radius: var(--radius);
|
|
45
|
-
border: 1px solid var(--border);
|
|
46
|
-
background: var(--surface-2);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.harbor-container {
|
|
50
|
-
border: 1px solid var(--border);
|
|
51
|
-
border-radius: var(--radius);
|
|
52
|
-
background: var(--surface);
|
|
53
|
-
overflow: hidden;
|
|
54
|
-
display: flex; flex-direction: column;
|
|
55
|
-
}
|
|
56
|
-
/* The state strip along the card's top, coloured by lifecycle state. */
|
|
57
|
-
.harbor-container__roof {
|
|
58
|
-
height: 4px;
|
|
59
|
-
background-color: var(--ok);
|
|
60
|
-
}
|
|
61
|
-
.harbor-container--parked .harbor-container__roof { background-color: var(--ink-faint); }
|
|
62
|
-
.harbor-container--pending .harbor-container__roof { background-color: var(--warn); }
|
|
63
|
-
.harbor-container--gone .harbor-container__roof { background-color: var(--border-strong); }
|
|
64
|
-
.harbor-container--error .harbor-container__roof { background-color: var(--danger); }
|
|
65
|
-
.harbor-container--blocked .harbor-container__roof { background-color: var(--danger); }
|
|
66
|
-
|
|
67
|
-
.harbor-container__body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
|
|
68
|
-
.harbor-container__head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
69
|
-
.harbor-container__who { color: var(--ink); font-weight: 600; font-size: 14.5px; }
|
|
70
|
-
.harbor-container__rank { color: var(--ink-faint); font-size: 12px; margin-left: 6px; font-weight: 400; }
|
|
71
|
-
|
|
72
|
-
.harbor-pill {
|
|
73
|
-
font-size: 11px; font-weight: 600;
|
|
74
|
-
letter-spacing: 0.04em; text-transform: uppercase;
|
|
75
|
-
padding: 2px 9px; border-radius: 999px; white-space: nowrap;
|
|
76
|
-
border: 1px solid var(--border); color: var(--ink-soft); background: var(--surface-2);
|
|
77
|
-
}
|
|
78
|
-
.harbor-pill--active { background: var(--ok-weak); border-color: color-mix(in srgb, var(--ok) 30%, transparent); color: var(--ok); }
|
|
79
|
-
.harbor-pill--pending { background: var(--warn-weak); border-color: color-mix(in srgb, var(--warn) 30%, transparent); color: var(--warn); }
|
|
80
|
-
.harbor-pill--blocked { background: var(--danger-weak); border-color: color-mix(in srgb, var(--danger) 30%, transparent); color: var(--danger); }
|
|
81
|
-
|
|
82
|
-
.harbor-rows { list-style: none; padding: 0; margin: 2px 0 0; }
|
|
83
|
-
.harbor-rows li {
|
|
84
|
-
display: flex; justify-content: space-between; gap: 12px;
|
|
85
|
-
padding: 4px 0; border-bottom: 1px solid var(--border);
|
|
86
|
-
font-size: 13px;
|
|
87
|
-
}
|
|
88
|
-
.harbor-rows li:last-child { border-bottom: none; }
|
|
89
|
-
.harbor-rows li .k { color: var(--ink-soft); }
|
|
90
|
-
.harbor-rows li .v { color: var(--ink); font-variant-numeric: tabular-nums; text-align: right; }
|
|
91
|
-
|
|
92
|
-
.harbor-blocked-note {
|
|
93
|
-
font-size: 12.5px; color: var(--danger);
|
|
94
|
-
border-left: 2px solid var(--danger); padding-left: 8px; margin: 2px 0 0;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.harbor-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 8px; }
|
|
98
|
-
.harbor-btn {
|
|
99
|
-
font: inherit; font-size: 12.5px; font-weight: 500;
|
|
100
|
-
padding: 5px 12px; border: 1px solid var(--border-strong);
|
|
101
|
-
background: var(--surface); color: var(--ink-soft);
|
|
102
|
-
border-radius: var(--radius-sm); cursor: pointer; flex: 1;
|
|
103
|
-
}
|
|
104
|
-
.harbor-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
|
|
105
|
-
.harbor-btn:disabled { opacity: 0.45; cursor: default; }
|
|
106
|
-
.harbor-btn--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
|
|
107
|
-
|
|
108
|
-
.harbor-empty, .harbor-sealed { color: var(--ink-soft); padding: 16px 0; }
|
|
109
|
-
|
|
110
|
-
/* Lightweight modal for confirm / block dialogs. Viewport-fixed overlay;
|
|
111
|
-
z-index sits above the shell's sidebar/drawer layers. */
|
|
112
|
-
.harbor-modal-bg {
|
|
113
|
-
position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 45%, transparent);
|
|
114
|
-
display: flex; align-items: center; justify-content: center; z-index: 200; padding: 20px;
|
|
115
|
-
}
|
|
116
|
-
.harbor-modal {
|
|
117
|
-
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
|
|
118
|
-
max-width: 460px; width: 100%; padding: 20px 22px;
|
|
119
|
-
box-shadow: var(--shadow-pop);
|
|
120
|
-
}
|
|
121
|
-
.harbor-modal h2 { color: var(--ink); margin: 0 0 8px; font-size: 16px; font-weight: 650; }
|
|
122
|
-
.harbor-modal p { color: var(--ink); font-size: 13.5px; margin: 0 0 12px; }
|
|
123
|
-
.harbor-modal label { display: block; font-size: 13px; color: var(--ink-soft); margin: 10px 0 4px; }
|
|
124
|
-
.harbor-modal input[type=text], .harbor-modal textarea {
|
|
125
|
-
width: 100%; box-sizing: border-box; font: inherit; font-size: 13.5px;
|
|
126
|
-
padding: 7px 9px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
|
|
127
|
-
background: var(--surface); color: var(--ink);
|
|
128
|
-
}
|
|
129
|
-
.harbor-modal__check { display: flex; align-items: flex-start; gap: 8px; margin: 12px 0 0; font-size: 13px; color: var(--ink); }
|
|
130
|
-
.harbor-modal__check input { margin-top: 3px; }
|
|
131
|
-
.harbor-modal__actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
|
|
132
|
-
</style>
|
|
13
|
+
<link rel="stylesheet" href="/builders/harbor.css">
|
|
133
14
|
</head>
|
|
134
15
|
<body data-page="harbor" data-page-title="Harbor">
|
|
135
16
|
|
|
@@ -161,6 +42,8 @@
|
|
|
161
42
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
162
43
|
|
|
163
44
|
<script src="/builders/shell.js?v=2026-07-02-shell1"></script>
|
|
45
|
+
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
46
|
+
<script src="/builders/palette.js" defer></script>
|
|
164
47
|
<script src="/builders/dom-utils.js?v=2026-06-16-harbor"></script>
|
|
165
48
|
<script src="/builders/harbor.js?v=2026-06-16-harbor"></script>
|
|
166
49
|
</body>
|