@bongos/core 1.24.78 → 1.24.80

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.
Files changed (369) hide show
  1. package/.bongos-core.json +498 -353
  2. package/.claude/skills/ask-for-help/SKILL.md +1 -1
  3. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  4. package/.claude/skills/design/SKILL.md +1 -1
  5. package/.claude/skills/goal-create/SKILL.md +1 -1
  6. package/.claude/skills/planning-session/SKILL.md +1 -1
  7. package/clients/bongos-client/README.md +1 -1
  8. package/clients/bongos-client/bongos-client.global.js +8 -0
  9. package/clients/bongos-client/index.cjs +8 -0
  10. package/clients/bongos-client/index.d.ts +11 -0
  11. package/clients/bongos-client/index.mjs +8 -0
  12. package/docs/adr/0274-one-kernel-three-role-packs.md +2 -2
  13. package/docs/adr/0399-the-visor-is-glass-over-the-scene-and-owns-no-camera.md +91 -0
  14. package/docs/adr/0400-a-chain-reserves-work-and-each-sub-quest-is-still-claimed-alone.md +109 -0
  15. package/docs/adr/0401-one-options-menu-opens-every-settings-screen-in-a-frame.md +53 -0
  16. package/docs/adr/README.md +3 -0
  17. package/docs/api/openapi.json +195 -3
  18. package/docs/api-reference.md +8 -4
  19. package/docs/architecture.md +7 -3
  20. package/docs/copy-inventory.md +390 -370
  21. package/docs/copy-registry.json +719 -518
  22. package/docs/design/characters/character-sprites-source.webp +0 -0
  23. package/docs/file-map.md +7 -8
  24. package/docs/module-api-changelog.md +4 -0
  25. package/docs/modules-contract.md +5 -0
  26. package/docs/onboarding/slash-commands.md +1 -1
  27. package/docs/packs/{engineer.md → artisan.md} +5 -5
  28. package/docs/packs/artist.md +50 -4
  29. package/docs/page-inventory.json +15 -4
  30. package/docs/page-readings.json +3182 -3336
  31. package/docs/{packs/ideator.md → recipes/ideation-playbook.md} +5 -48
  32. package/migrations/core_296_crafts_artisan_artist.sql +72 -0
  33. package/migrations/core_297_builder_character.sql +30 -0
  34. package/modules/copy-desk/proposals.js +1 -1
  35. package/modules/economy/credits-by-craft.js +29 -15
  36. package/modules/hall-ui/public/ai-studio.html +4 -4
  37. package/modules/hall-ui/public/atlas.html +5 -5
  38. package/modules/hall-ui/public/atlas.js +3 -1
  39. package/modules/hall-ui/public/blockers.html +5 -5
  40. package/modules/hall-ui/public/board-room.html +4 -4
  41. package/modules/hall-ui/public/characters/artisan.png +0 -0
  42. package/modules/hall-ui/public/characters/artist.png +0 -0
  43. package/modules/hall-ui/public/characters/patron.png +0 -0
  44. package/modules/hall-ui/public/city.css +2 -1
  45. package/modules/hall-ui/public/city.html +9 -6
  46. package/modules/hall-ui/public/city.js +7 -1
  47. package/modules/hall-ui/public/collab.html +4 -4
  48. package/modules/hall-ui/public/commands.html +4 -4
  49. package/modules/hall-ui/public/copy-desk.html +4 -4
  50. package/modules/hall-ui/public/craft-mode.js +258 -64
  51. package/modules/hall-ui/public/deploy.html +4 -4
  52. package/modules/hall-ui/public/diagram-viewer.js +2 -1
  53. package/modules/hall-ui/public/dom-utils.js +1 -1
  54. package/modules/hall-ui/public/goal-map.html +9 -6
  55. package/modules/hall-ui/public/goals.html +5 -5
  56. package/modules/hall-ui/public/government.html +4 -4
  57. package/modules/hall-ui/public/hall-render.js +3 -1
  58. package/modules/hall-ui/public/home-city-draw.js +3 -3
  59. package/modules/hall-ui/public/home-city.css +4 -0
  60. package/modules/hall-ui/public/home-city.js +17 -9
  61. package/modules/hall-ui/public/home-gallery.js +8 -1
  62. package/modules/hall-ui/public/home-idea-box.css +2 -2
  63. package/modules/hall-ui/public/home-idea-box.js +3 -3
  64. package/modules/hall-ui/public/idea.html +5 -5
  65. package/modules/hall-ui/public/ideas.html +5 -5
  66. package/modules/hall-ui/public/index.html +11 -7
  67. package/modules/hall-ui/public/market-watch-item.html +4 -4
  68. package/modules/hall-ui/public/market-watch-rules.html +4 -4
  69. package/modules/hall-ui/public/market-watch.html +6 -9
  70. package/modules/hall-ui/public/market-watch.js +22 -45
  71. package/modules/hall-ui/public/modules.html +4 -4
  72. package/modules/hall-ui/public/money.html +4 -4
  73. package/modules/hall-ui/public/my-agents.html +4 -4
  74. package/modules/hall-ui/public/options-menu.js +409 -0
  75. package/modules/hall-ui/public/paintbrush.js +3 -3
  76. package/modules/hall-ui/public/palette.js +11 -13
  77. package/modules/hall-ui/public/primer.html +5 -5
  78. package/modules/hall-ui/public/profile-crafts.js +1 -1
  79. package/modules/hall-ui/public/profile-roles.js +23 -19
  80. package/modules/hall-ui/public/profile.css +1 -1
  81. package/modules/hall-ui/public/profile.html +19 -18
  82. package/modules/hall-ui/public/profile.js +19 -18
  83. package/modules/hall-ui/public/profile.states.json +4 -4
  84. package/modules/hall-ui/public/project-settings.html +4 -4
  85. package/modules/hall-ui/public/roster.html +4 -4
  86. package/modules/hall-ui/public/roster.js +3 -3
  87. package/modules/hall-ui/public/settings.css +24 -4
  88. package/modules/hall-ui/public/settings.html +21 -17
  89. package/modules/hall-ui/public/settings.js +44 -44
  90. package/modules/hall-ui/public/shell-game.css +65 -0
  91. package/modules/hall-ui/public/shell-game.js +283 -3
  92. package/modules/hall-ui/public/shell.js +7 -26
  93. package/modules/hall-ui/public/sky-interaction.js +7 -0
  94. package/modules/hall-ui/public/speciality-tools.js +1 -2
  95. package/modules/hall-ui/public/street-inside.js +3 -4
  96. package/modules/hall-ui/public/street.html +4 -4
  97. package/modules/hall-ui/public/studio.html +5 -5
  98. package/modules/hall-ui/public/style.css +73 -47
  99. package/modules/hall-ui/public/task-detail.js +5 -4
  100. package/modules/hall-ui/public/task.html +5 -5
  101. package/modules/hall-ui/public/thinking.css +10 -0
  102. package/modules/hall-ui/public/thinking.html +9 -6
  103. package/modules/hall-ui/public/tweak-editor.html +5 -5
  104. package/modules/hall-ui/public/tweak-editor.js +5 -1
  105. package/modules/hall-ui/public/update-pill.js +91 -2
  106. package/modules/hall-ui/public/visor.css +80 -0
  107. package/modules/hall-ui/public/visor.js +316 -0
  108. package/modules/hall-ui/public/watch-repo-invite.js +159 -0
  109. package/modules/hall-ui/public/watch.html +6 -5
  110. package/modules/hall-ui/public/watch.js +17 -2
  111. package/modules/hall-ui/public/welcome-boot.js +15 -6
  112. package/modules/hall-ui/public/work.html +5 -5
  113. package/modules/hall-ui/records/builders-roster.md +2 -2
  114. package/modules/hall-ui/records/craft-mode.md +13 -11
  115. package/modules/hall-ui/records/game-mode.md +2 -2
  116. package/modules/hall-ui/records/governor-street.md +1 -1
  117. package/modules/hall-ui/records/home-city.md +3 -1
  118. package/modules/hall-ui/records/market-watch-settings.md +2 -0
  119. package/modules/hall-ui/records/options-menu.md +15 -0
  120. package/modules/hall-ui/records/profile-roles.md +11 -11
  121. package/modules/hall-ui/records/sky.md +3 -3
  122. package/modules/hall-ui/records/start-screen.md +21 -0
  123. package/modules/hall-ui/records/tweak-editor.md +1 -1
  124. package/modules/hall-ui/records/update-pill.md +12 -0
  125. package/modules/hall-ui/records/visor.md +23 -0
  126. package/modules/hall-ui/records/welcome-tower.md +5 -5
  127. package/modules/ideas/ideator-stats.js +3 -1
  128. package/modules/ideas/inbox.js +2 -2
  129. package/modules/lifecycle/activity.js +1 -1
  130. package/modules/lifecycle/cascade.js +4 -4
  131. package/modules/lifecycle/goal-spec-task.js +1 -1
  132. package/modules/lifecycle/help-requests.js +19 -15
  133. package/modules/lifecycle/kickoff-checklist.js +3 -3
  134. package/modules/lifecycle/kickoff-seed.js +1 -1
  135. package/modules/lifecycle/migrations/lifecycle_021_crafts_artisan_artist.sql +29 -0
  136. package/modules/lifecycle/mingle.js +4 -4
  137. package/modules/lifecycle/page-tweak-write.js +1 -1
  138. package/modules/lifecycle/routes/task-write-routes.js +3 -1
  139. package/modules/lifecycle/routes/tasks.js +3 -3
  140. package/modules/lifecycle/ship-card.js +2 -3
  141. package/modules/lifecycle/task-classifier.js +39 -29
  142. package/modules/lifecycle/tests/cascade.mjs +7 -7
  143. package/modules/onboarding/founding-mode.js +3 -0
  144. package/modules/onboarding/genesis-home.js +21 -1
  145. package/modules/onboarding/routes/onboarding.js +2 -0
  146. package/modules/page-notes/notes.js +3 -2
  147. package/modules/page-notes/split.js +1 -1
  148. package/modules/platform-identity/craft-rollup.js +35 -7
  149. package/modules/platform-identity/migrations/platform_identity_036_crafts_artisan_artist.sql +45 -0
  150. package/modules/platform-identity/platform-identity.js +2 -2
  151. package/modules/platform-identity/routes/community-leaderboard.js +2 -1
  152. package/modules/platform-identity/routes/community-search.js +2 -1
  153. package/modules/platform-identity/routes/sso.js +2 -1
  154. package/modules/platform-identity/tests/platform-identity.mjs +6 -6
  155. package/modules/public-landing/public/community.html +3 -5
  156. package/modules/public-landing/public/index.html +1 -1
  157. package/modules/public-landing/public/projects.html +1 -1
  158. package/modules/specialities/migrations/specialities_004_crafts_artisan_artist.sql +30 -0
  159. package/modules/specialities/routes/specialities.js +2 -2
  160. package/modules/status-ui/public/status.js +1 -1
  161. package/modules/ui-design/kit/fixtures/community-leaderboard.json +10 -10
  162. package/modules/ui-design/kit/fixtures/community-search.json +2 -2
  163. package/modules/ui-design/kit/fixtures/scouting-recruiter.json +1 -1
  164. package/package-lock.json +2 -2
  165. package/package.json +1 -1
  166. package/release-notes.json +76 -0
  167. package/scripts/bongos/autobongos-host.js +19 -4
  168. package/scripts/bongos/autobongos-loop.js +1 -1
  169. package/scripts/bongos/claude-materialize.js +20 -1
  170. package/scripts/bongos/discipline-modes.json +7 -12
  171. package/scripts/bongos/fitness.js +1 -1
  172. package/scripts/bongos/gen-hall-sitemap.js +7 -7
  173. package/scripts/bongos/grade-smoke.js +2 -2
  174. package/scripts/bongos/init.js +2 -2
  175. package/scripts/bongos/newcomer-floor.config.json +1 -2
  176. package/scripts/bongos/newcomer-floor.js +4 -3
  177. package/scripts/bongos/newcomer-floor.templates.json +10 -12
  178. package/scripts/bongos/newcomer-floor.test.js +47 -38
  179. package/scripts/bongos/role-pack-guard.js +5 -4
  180. package/scripts/bongos/seed-tasks.example.json +3 -3
  181. package/scripts/bongos/setup.js +20 -107
  182. package/scripts/bongos/start.js +2 -2
  183. package/scripts/bongos/task.js +5 -4
  184. package/scripts/bongos/triage.js +1 -1
  185. package/scripts/bongos/worktree.js +16 -4
  186. package/scripts/setup-builder.js +6 -46
  187. package/src/bongos/auth-admission.js +8 -8
  188. package/src/bongos/craft-mode.js +2 -0
  189. package/src/bongos/db.js +39 -1
  190. package/src/bongos/github-repos.js +78 -0
  191. package/src/bongos/module-scope-map.js +22 -0
  192. package/src/bongos/role-stats.js +27 -11
  193. package/src/bongos/routes/github.js +100 -2
  194. package/src/bongos/routes/me.js +33 -0
  195. package/src/bongos/serve-internal.js +26 -9
  196. package/src/crafts.js +66 -0
  197. package/src/module-api.js +6 -1
  198. package/src/module-loader/manifest-schema.js +16 -0
  199. package/src/modules.js +2 -2
  200. package/src/role-responsibilities.js +6 -5
  201. package/tests/acclaim_feed_evidence_db.mjs +1 -1
  202. package/tests/activity_rollup_as_of.mjs +1 -1
  203. package/tests/api_alias_caller_ratchet.mjs +3 -3
  204. package/tests/application_lifecycle.mjs +1 -1
  205. package/tests/artist_review.mjs +1 -1
  206. package/tests/artist_review_goal.mjs +1 -1
  207. package/tests/autobongos_host.mjs +19 -1
  208. package/tests/blocker_hall_live_proof.mjs +1 -1
  209. package/tests/blocker_tasks_named_db.mjs +2 -2
  210. package/tests/canonical_profile_url.mjs +1 -1
  211. package/tests/cap_newcomer_tasks.mjs +13 -13
  212. package/tests/character_creation.mjs +294 -0
  213. package/tests/claim_gate_open_blocker.mjs +2 -2
  214. package/tests/claim_gate_rebase.mjs +6 -6
  215. package/tests/claude_materialize.mjs +75 -1
  216. package/tests/clawback_confirmed_backlog.mjs +3 -3
  217. package/tests/collab_page.mjs +8 -9
  218. package/tests/collab_self_settling.mjs +2 -2
  219. package/tests/community_leaderboard_route.mjs +13 -5
  220. package/tests/community_proof_db.mjs +3 -0
  221. package/tests/community_search_route.mjs +7 -6
  222. package/tests/conductor.mjs +1 -1
  223. package/tests/conductor_main_e2e.mjs +8 -8
  224. package/tests/copy_desk_flags_db.mjs +1 -1
  225. package/tests/copy_desk_page_approve.mjs +2 -2
  226. package/tests/copy_desk_page_claim.mjs +2 -2
  227. package/tests/copy_desk_page_next.mjs +1 -1
  228. package/tests/copy_desk_page_release.mjs +1 -1
  229. package/tests/copy_desk_page_submit.mjs +2 -2
  230. package/tests/core_258_box_session_claims_db.mjs +1 -1
  231. package/tests/craft_mode.mjs +48 -34
  232. package/tests/craft_mode_home.mjs +20 -20
  233. package/tests/craft_mode_looks.mjs +16 -15
  234. package/tests/craft_mode_nav.mjs +31 -29
  235. package/tests/craft_review_mode.mjs +46 -41
  236. package/tests/crafts_vocabulary.mjs +70 -0
  237. package/tests/cross_discipline_priority_direction.mjs +5 -5
  238. package/tests/fitness.mjs +7 -11
  239. package/tests/funded_project_pays_proof_db.mjs +1 -1
  240. package/tests/genesis_home.mjs +21 -1
  241. package/tests/github_chip.mjs +3 -3
  242. package/tests/github_repo_invite.mjs +379 -0
  243. package/tests/goal_criterion_confirm_ui.mjs +1 -1
  244. package/tests/goal_invite_consent.mjs +1 -1
  245. package/tests/goal_map_page.mjs +2 -2
  246. package/tests/goal_sort_staleness.mjs +1 -1
  247. package/tests/goal_spec_task.mjs +1 -1
  248. package/tests/goal_spec_task_db.mjs +3 -3
  249. package/tests/grade_engine.mjs +2 -2
  250. package/tests/grader_no_artifact.mjs +1 -1
  251. package/tests/grader_prompt_fencing.mjs +1 -1
  252. package/tests/grader_prompt_window_bound.mjs +1 -1
  253. package/tests/grader_reader_lens.mjs +2 -2
  254. package/tests/grader_severity_gate.mjs +1 -1
  255. package/tests/grader_unbacked_score.mjs +1 -1
  256. package/tests/hall_approval_queue.mjs +1 -1
  257. package/tests/hall_board_world.mjs +2 -2
  258. package/tests/hall_builders_page_pass.mjs +1 -1
  259. package/tests/hall_city.mjs +1 -1
  260. package/tests/hall_fullscreen.mjs +27 -3
  261. package/tests/hall_kit_charts.mjs +1 -1
  262. package/tests/hall_landing_boot.mjs +1 -1
  263. package/tests/hall_my_agents.mjs +16 -16
  264. package/tests/hall_nav.mjs +22 -15
  265. package/tests/hall_options_menu.mjs +247 -0
  266. package/tests/hall_oversight_world.mjs +1 -1
  267. package/tests/hall_palette.mjs +8 -9
  268. package/tests/hall_profile_world.mjs +3 -3
  269. package/tests/hall_record_world.mjs +2 -2
  270. package/tests/hall_settings_world.mjs +2 -1
  271. package/tests/hall_sitemap.mjs +6 -5
  272. package/tests/hall_start_screen.mjs +244 -0
  273. package/tests/hall_street.mjs +2 -2
  274. package/tests/hall_street_inside.mjs +17 -9
  275. package/tests/hall_studio_world.mjs +3 -3
  276. package/tests/hall_visor.mjs +224 -0
  277. package/tests/help_requests.mjs +47 -15
  278. package/tests/helpers.mjs +4 -4
  279. package/tests/home_city.mjs +6 -4
  280. package/tests/home_city_widget.mjs +33 -14
  281. package/tests/home_gallery_widget.mjs +4 -4
  282. package/tests/home_idea_box.mjs +6 -6
  283. package/tests/hub_community_page.mjs +3 -3
  284. package/tests/hub_craft_rollup.mjs +75 -36
  285. package/tests/hub_recent_ships.mjs +3 -2
  286. package/tests/idea_cascade.mjs +2 -2
  287. package/tests/idea_credit_streams_db.mjs +1 -1
  288. package/tests/idea_detail_page.mjs +1 -1
  289. package/tests/idea_ideate_full.mjs +5 -2
  290. package/tests/idea_spark_hall.mjs +1 -1
  291. package/tests/init.mjs +3 -3
  292. package/tests/instance_manifest.mjs +2 -2
  293. package/tests/kickoff_checklist.mjs +1 -1
  294. package/tests/leaderboard_roles.mjs +34 -25
  295. package/tests/lifecycle_claim_ladder_refs.mjs +55 -0
  296. package/tests/lightbulb.mjs +14 -10
  297. package/tests/main_discipline.mjs +8 -8
  298. package/tests/markdown_line_endings.mjs +1 -1
  299. package/tests/market_watch_pages.mjs +52 -74
  300. package/tests/me_streak_leaderboard_queries.mjs +3 -3
  301. package/tests/migration_allocation.mjs +1 -1
  302. package/tests/mingle.mjs +36 -21
  303. package/tests/module-scope-map.mjs +22 -2
  304. package/tests/module_api.mjs +1 -0
  305. package/tests/module_contributions.mjs +13 -13
  306. package/tests/module_manifest.mjs +29 -0
  307. package/tests/module_skills_hook.mjs +2 -2
  308. package/tests/modules.mjs +14 -7
  309. package/tests/nav_permission_atoms.mjs +2 -1
  310. package/tests/needs_rebase.mjs +1 -1
  311. package/tests/newcomer_restock.mjs +13 -13
  312. package/tests/page_notes_panel.mjs +22 -22
  313. package/tests/page_tweak_no_block.mjs +1 -1
  314. package/tests/paintbrush.mjs +7 -7
  315. package/tests/privacy_matrix.mjs +1 -0
  316. package/tests/profile_activity.mjs +20 -23
  317. package/tests/profile_earnings.mjs +1 -1
  318. package/tests/profile_nudge_prefs.mjs +4 -4
  319. package/tests/profile_role_headline.mjs +73 -46
  320. package/tests/profile_role_stats.mjs +55 -45
  321. package/tests/profile_rollup_consent.mjs +19 -6
  322. package/tests/profile_route.mjs +12 -12
  323. package/tests/profile_ui_cross_project.mjs +4 -4
  324. package/tests/project_invite_suggestions.mjs +2 -2
  325. package/tests/promote_goal_id.mjs +1 -1
  326. package/tests/publish_manifest.mjs +1 -1
  327. package/tests/rank_floor_wiring.mjs +1 -1
  328. package/tests/regrade_actual_minutes.mjs +1 -1
  329. package/tests/removal_proposal.mjs +2 -2
  330. package/tests/reward_gate.mjs +4 -4
  331. package/tests/reward_mode_cost_plus_only.mjs +1 -1
  332. package/tests/role_responsibilities.mjs +18 -12
  333. package/tests/role_stats_db.mjs +17 -16
  334. package/tests/scouting_rollup_fanout.mjs +5 -5
  335. package/tests/seed_tasks.mjs +5 -2
  336. package/tests/session_earnings_mirror_db.mjs +1 -1
  337. package/tests/session_reward_on_land_db.mjs +1 -1
  338. package/tests/session_reward_reconcile_db.mjs +2 -2
  339. package/tests/sessions_kit_pager.mjs +1 -1
  340. package/tests/settings_art_key_absent.mjs +2 -2
  341. package/tests/settings_main_role.mjs +21 -20
  342. package/tests/setup_flow.mjs +3 -3
  343. package/tests/setup_smoke.mjs +20 -0
  344. package/tests/ship_card.mjs +6 -6
  345. package/tests/specialities.mjs +16 -4
  346. package/tests/speciality_db_shape.mjs +6 -6
  347. package/tests/speciality_injection.mjs +17 -17
  348. package/tests/speciality_offer_ui.mjs +5 -5
  349. package/tests/speciality_offered.mjs +6 -5
  350. package/tests/speciality_session_skills.mjs +7 -7
  351. package/tests/speciality_skills.mjs +11 -11
  352. package/tests/speciality_walkthrough_ui.mjs +2 -2
  353. package/tests/sso_checkin_identity_spoof.mjs +2 -1
  354. package/tests/task_classifier_vocab.mjs +10 -0
  355. package/tests/task_cli.mjs +11 -3
  356. package/tests/task_criteria_unlink_db.mjs +2 -2
  357. package/tests/task_discipline_required.mjs +38 -16
  358. package/tests/task_goal_required.mjs +4 -4
  359. package/tests/task_needs_db.mjs +1 -1
  360. package/tests/tweak_replaces_artist_review.mjs +1 -1
  361. package/tests/update_pill.mjs +153 -2
  362. package/tests/upkeep_home.mjs +1 -1
  363. package/tests/v3_c1_options_proof.mjs +145 -0
  364. package/tests/visual_review.mjs +3 -3
  365. package/tests/watch_applications_queue.mjs +8 -5
  366. package/tests/watch_sealed_floor.mjs +3 -1
  367. package/tests/welcome_boot.mjs +12 -9
  368. package/tests/welcome_boot_browser.mjs +13 -13
  369. package/tests/worktree_helper.mjs +16 -1
@@ -621,8 +621,7 @@
621
621
  <span>Role it sits under</span>
622
622
  <select name="discipline" required>
623
623
  <option value="">Pick one…</option>
624
- <option value="engineer">Engineer</option>
625
- <option value="ideator">Ideator</option>
624
+ <option value="artisan">Artisan</option>
626
625
  <option value="artist">Artist</option>
627
626
  <option value="ui">UI design</option>
628
627
  </select>
@@ -81,7 +81,6 @@
81
81
  let top = h;
82
82
  if (craft === 'artist') { const bh = Math.round(h * 0.8); S.box(out, T, x, 0, w, bh, T.work, { d: 6, win: true, lit: lit }); S.sawtooth(out, x, -bh, w, 3, 12, T.roof, T.glass); top = bh + 12; }
83
83
  else if (craft === 'ui') { S.box(out, T, x, 0, w, h, T.glass, { d: 6, grid: 3 }); S.box(out, T, x - 2, 0, w + 4, 4, T.roof, { d: 6, z: h }); top = h + 4; }
84
- else if (craft === 'ideator') { S.box(out, T, x, 0, w, 22, T.work, { d: 6, door: true }); S.gable(out, x, -22, w, 14, T.roof); top = 36; }
85
84
  else S.box(out, T, x, 0, w, h, T.work, { d: 6, win: true, lit: lit });
86
85
  if (!lit) {
87
86
  const fx = x + w / 2;
@@ -410,7 +409,7 @@
410
409
  stageEdge: p.draw === 'awaiting a tester' ? 'rgba(251,149,105,0.6)' : T.ruleStrong,
411
410
  })),
412
411
  legend: [
413
- { key: 'a', text: 'Shape is the craft: tower for engineer, studio roof for artist, glass front for UI, a small pavilion for ideator.' },
412
+ { key: 'a', text: 'Shape is the craft: tower for artisan, studio roof for artist, glass front for UI.' },
414
413
  { key: 'b', text: 'Stage is the status: staked plot, slab, scaffold, built, then lit once shipped. A flag means it waits on a check.' },
415
414
  ],
416
415
  };
@@ -670,7 +669,7 @@
670
669
  }
671
670
 
672
671
  // ---------- the real districts ----------
673
- const CRAFTS = Object.freeze(['engineer', 'artist', 'ui', 'ideator']);
672
+ const CRAFTS = Object.freeze(['artisan', 'artist', 'ui']);
674
673
  // A task's status as the prototype's construction stage: [drawing stage, pill words].
675
674
  const STAGES = Object.freeze({
676
675
  shipped: ['shipped', 'shipped'], confirmed: ['graded · landing', 'graded · landing'], completed: ['being graded', 'being graded'],
@@ -699,7 +698,7 @@
699
698
  const shown = mine.slice().sort((a, b) => rank(a) - rank(b) || recent(a) - recent(b) || Number(a.id) - Number(b.id)).slice(0, MAX_ITEMS)
700
699
  .sort((a, b) => PIPELINE.indexOf(a.status) - PIPELINE.indexOf(b.status) || Number(a.id) - Number(b.id));
701
700
  const items = shown.map((t) => {
702
- const craft = CRAFTS.indexOf(t.discipline) >= 0 ? t.discipline : 'engineer';
701
+ const craft = CRAFTS.indexOf(t.discipline) >= 0 ? t.discipline : 'artisan';
703
702
  const st = STAGES[t.status];
704
703
  const built = ['ready', 'backlog'].indexOf(st[0]) < 0;
705
704
  return [String(t.title || 'task ' + t.id), String(t.kind || 'task'), craft, st[0], built ? taskHeight(t) : 0, st[1], '/builders/task/' + encodeURIComponent(t.id)];
@@ -10,7 +10,7 @@
10
10
  <!-- The faces (Manrope, JetBrains Mono) come from the branding pack's font
11
11
  links, injected into this head by the server like every hall page's
12
12
  (tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet). -->
13
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
13
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
14
14
  <link rel="stylesheet" href="/builders/street.css?v=2026-10-09-living3">
15
15
  <link rel="stylesheet" href="/builders/street-card.css?v=2026-10-04-record1">
16
16
  <link rel="stylesheet" href="/builders/street-deck.css?v=2026-10-17-tidy">
@@ -229,10 +229,10 @@
229
229
  </div>
230
230
 
231
231
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
232
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
232
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
233
233
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
234
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
235
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
234
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
235
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
236
236
  <script src="/builders/hall-dialog.js"></script>
237
237
  <script src="/builders/palette.js" defer></script>
238
238
  <script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
13
13
  <link rel="preconnect" href="https://fonts.googleapis.com">
14
14
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
15
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
16
16
  <link rel="stylesheet" href="/builders/studio.css?v=2026-10-09-day">
17
17
  <link rel="stylesheet" href="/builders/approval-queue.css?v=2026-09-29-aqfix">
18
18
  <link rel="stylesheet" href="/builders/home-gallery.css?v=2026-11-04-studio">
@@ -222,10 +222,10 @@
222
222
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
223
223
 
224
224
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
225
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
225
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
226
226
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
227
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
228
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
227
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
228
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
229
229
  <script src="/builders/hall-dialog.js"></script>
230
230
  <script src="/builders/palette.js" defer></script>
231
231
  <!-- The kit, for its ONE renderer: the full-size ship-time visual figure
@@ -243,7 +243,7 @@
243
243
  <script src="/builders/studio-lib.js?v=2026-10-09-day"></script>
244
244
  <script src="/builders/ai-studio-lib.js?v=2026-10-29-ais1"></script>
245
245
  <script src="/builders/studio.js?v=2026-10-09-day"></script>
246
- <script src="/builders/home-gallery.js?v=2026-11-04-studio"></script>
246
+ <script src="/builders/home-gallery.js?v=2026-11-10-options"></script>
247
247
  <script src="/builders/home-studio.js?v=2026-11-04-studio"></script>
248
248
  </body>
249
249
  </html>
@@ -712,6 +712,16 @@ html[data-theme="dark"] .brand-mark__mark { --mark-ink: #e2e1e4; }
712
712
  .founding-band { flex-wrap: wrap; row-gap: 2px; padding: 8px 16px; }
713
713
  .founding-band__desc { display: none; }
714
714
  .founding-band__stage { margin-left: 0; white-space: normal; }
715
+ /* task 1005148, the visor (visor.css): the top of a phone belongs to the scene and the shell’s
716
+ corner buttons, so the compass and the place line step aside and all three pills share the
717
+ bottom row: the main action, Actions (its dots and key only), the sprite with the credits. */
718
+ html[data-game="on"] .visor:not([hidden]) { --visor-inset-right: var(--ds-space-gutter-narrow); --visor-inset-left: var(--ds-space-gutter-narrow); --visor-inset-bottom: 40px; }
719
+ html[data-game="on"] .visor__place, html[data-game="on"] .visor__cell, html[data-game="on"] .visor__mark { display: none; }
720
+ html[data-game="on"] .visor__pill--actions { top: auto; right: auto; left: 50%; bottom: var(--visor-inset-bottom); transform: translateX(-50%); padding: 0 var(--ds-space-xs); }
721
+ html[data-game="on"] .visor__pill--actions > span:not(.visor__dots) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
722
+ html[data-game="on"] .visor__sheet { top: auto; bottom: calc(var(--visor-inset-bottom) + 56px); right: var(--visor-inset-right); max-height: 70vh; }
723
+ html[data-game="on"] .visor__me .visor__name { display: none; }
724
+ html[data-game="on"] .visor__me { padding: 4px var(--ds-space-xs) 4px 4px; }
715
725
  }
716
726
  /* task 1004424 (BV2.PS10): THE FOUNDING MARK. A pill in .rank-badge's grammar (same
717
727
  height, type and radius) so it sits beside a rank without competing with it; the
@@ -1255,7 +1265,15 @@ html[data-fullscreen="on"] .app-topbar {
1255
1265
  pointer-events: none;
1256
1266
  }
1257
1267
  html[data-fullscreen="on"] .app-topbar > :not(.topbar-side),
1258
- html[data-fullscreen="on"] .topbar-side > :not(.fullscreen-toggle) { display: none; }
1268
+ html[data-fullscreen="on"] .topbar-side > :not(.fullscreen-toggle):not(.upd-pill) { display: none; }
1269
+ /* task 1005191: the Update pill stays with the bars away. Game mode opens every page
1270
+ this way, and an update nobody can see is an update nobody takes. */
1271
+ html[data-fullscreen="on"] .upd-pill {
1272
+ pointer-events: auto;
1273
+ min-height: 36px;
1274
+ margin-right: 8px;
1275
+ box-shadow: var(--shadow-pop);
1276
+ }
1259
1277
  /* task 1004430: the way back must read on ANY ground. The hall's glass is
1260
1278
  near-clear, so over the black sky in the light theme it was a dark glyph on
1261
1279
  black — the page looked stuck without its bars. The card tone plus a drop
@@ -1281,6 +1299,16 @@ html[data-fullscreen="on"] .fullscreen-toggle:hover { color: var(--accent-ink);
1281
1299
  /* A page with no full-screen layout of its own steps its content clear of the
1282
1300
  corner button; the sky and the studio lay themselves out (shell.js `plain`). */
1283
1301
  html[data-fullscreen="on"][data-fullscreen-plain="on"] .app-content { padding-top: 60px; }
1302
+ /* EMBEDDED (html[data-embed="on"], shell-game.js; task 1005144, ADR 0401): a screen
1303
+ opened inside the options menu's frame. The menu is the chrome, so the page keeps
1304
+ none of its own — no sidebar, scrim, foot or top bar — and sits on the frame's
1305
+ ground. The page keeps its one <header> in the DOM (hidden), as full screen does. */
1306
+ html[data-embed="on"] .app-sidebar,
1307
+ html[data-embed="on"] .app-scrim,
1308
+ html[data-embed="on"] .app-foot,
1309
+ html[data-embed="on"] .app-topbar { display: none; }
1310
+ html[data-embed="on"] .app-body { margin-left: 0; }
1311
+ html[data-embed="on"] .app-content { padding-top: 0; }
1284
1312
  /* Said once on entering, since the choice is remembered and a page can open in it. */
1285
1313
  .fullscreen-hint {
1286
1314
  position: fixed;
@@ -1313,7 +1341,8 @@ html[data-fullscreen="on"][data-fullscreen-plain="on"] .app-content { padding-to
1313
1341
  flex-shrink: 0;
1314
1342
  }
1315
1343
  .craft-switch__opt,
1316
- .craft-switch__open {
1344
+ .craft-switch__open,
1345
+ .craft-switch__me {
1317
1346
  display: inline-flex;
1318
1347
  align-items: center;
1319
1348
  gap: 6px;
@@ -1330,10 +1359,12 @@ html[data-fullscreen="on"][data-fullscreen-plain="on"] .app-content { padding-to
1330
1359
  white-space: nowrap;
1331
1360
  }
1332
1361
  .craft-switch__opt:hover,
1333
- .craft-switch__open:hover { color: var(--ink); background: var(--glass); }
1362
+ .craft-switch__open:hover,
1363
+ .craft-switch__me:hover { color: var(--ink); background: var(--glass); }
1334
1364
  .craft-switch__opt[aria-pressed="true"] { color: var(--ink); background: var(--glass-strong); }
1335
1365
  .craft-switch__opt:focus-visible,
1336
- .craft-switch__open:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
1366
+ .craft-switch__open:focus-visible,
1367
+ .craft-switch__me:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
1337
1368
  .craft-switch__icon { width: 15px; height: 15px; flex-shrink: 0; }
1338
1369
  .craft-switch__open { display: none; }
1339
1370
  @media (max-width: 1180px) {
@@ -1344,7 +1375,23 @@ html[data-fullscreen="on"][data-fullscreen-plain="on"] .app-content { padding-to
1344
1375
  .craft-switch { padding: 2px; }
1345
1376
  .craft-switch__opt[aria-pressed="false"] { display: none; }
1346
1377
  .craft-switch--unset .craft-switch__open { display: inline-flex; padding: 0 7px; }
1347
- }
1378
+ .craft-switch__me { padding: 0 2px; }
1379
+ .craft-switch__me .craft-switch__label { display: none; }
1380
+ }
1381
+
1382
+ /* THE CHARACTER (task 1005147). A builder who holds a character wears its sprite in
1383
+ the top bar in place of the switch: one button, which offers "Change character"
1384
+ (signing out). The sprites are pixel art, so they scale by whole pixels. */
1385
+ .craft-sprite { display: block; image-rendering: pixelated; object-fit: contain; }
1386
+ .craft-switch__me { padding: 0 10px 0 4px; color: var(--ink); }
1387
+ /* The chip is the figure's head: the portrait cropped round its top third. */
1388
+ .craft-sprite--chip { width: 26px; height: 26px; border-radius: var(--radius-pill); object-fit: cover; object-position: 50% 22%; }
1389
+ /* Character creation: each door is the owner's portrait — the figure on its plinth
1390
+ in the torch-lit hall — filling the top of the door, the words beneath it. */
1391
+ .craft-plinth { display: block; overflow: hidden; }
1392
+ .craft-sprite--door { width: 100%; height: auto; aspect-ratio: 250 / 290; transition: transform 200ms cubic-bezier(.2, .7, .3, 1); }
1393
+ .craft-door--character:hover .craft-sprite--door,
1394
+ .craft-door--character:focus-visible .craft-sprite--door { transform: scale(1.03); }
1348
1395
 
1349
1396
  /* The picker: a dialog over a scrim, four doors in a row above the
1350
1397
  "ask me again" box. Each door carries its scene from the approved prototype,
@@ -1427,7 +1474,8 @@ html.setup-gate-open { overflow: hidden; }
1427
1474
  .setup-gate__craft[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-tint); }
1428
1475
  /* The save is the shared primary door (controls.css, task 1005084). */
1429
1476
  .setup-gate__save { margin-top: 12px; }
1430
- .setup-gate__err { margin: 8px 0 0; font-size: 14px; color: var(--danger); }
1477
+ .setup-gate__err,
1478
+ .craft-picker__error { margin: 8px 0 0; font-size: 14px; color: var(--danger); }
1431
1479
  .setup-gate__foot { margin: 24px 0 0; font-size: 14px; }
1432
1480
  .setup-gate__foot a { color: var(--ink-soft); }
1433
1481
  @media (max-width: 640px) { .setup-gate__panel { padding: 28px 20px 20px; border-radius: 18px; } }
@@ -1525,9 +1573,9 @@ html.setup-gate-open { overflow: hidden; }
1525
1573
  overflow: hidden;
1526
1574
  background: #101012;
1527
1575
  }
1528
- .craft-art--artistry { background: #0c1122; }
1576
+ .craft-art--artist { background: #0c1122; }
1529
1577
  .craft-art--ideating { background: #05060d; }
1530
- .craft-art--governing { background: #000; }
1578
+ .craft-art--patron { background: #000; }
1531
1579
  .craft-art__dot { position: absolute; border-radius: 999px; box-sizing: border-box; }
1532
1580
  .craft-art__dot--star { background: #d8dcf0; }
1533
1581
  .craft-art__dot--lit { background: var(--accent); border-radius: 0; }
@@ -1592,6 +1640,11 @@ html.setup-gate-open { overflow: hidden; }
1592
1640
  .craft-door__head { padding: 10px 16px 0; }
1593
1641
  .craft-door__name { font-size: 18px; }
1594
1642
  .craft-door__line { flex: 0 0 100%; padding: 0 16px; box-sizing: border-box; }
1643
+ /* A phone stacks the three as rows: the portrait on the left, the words beside it. */
1644
+ .craft-door.craft-door--character { display: grid; grid-template-columns: 86px minmax(0, 1fr); grid-template-rows: auto 1fr; align-content: start; gap: 4px 14px; padding: 0; }
1645
+ .craft-plinth { grid-row: 1 / span 2; width: 86px; }
1646
+ .craft-door.craft-door--character > .craft-door__head { padding: 12px 14px 0 0; }
1647
+ .craft-door.craft-door--character > .craft-door__line { padding: 0 14px 12px 0; }
1595
1648
  }
1596
1649
 
1597
1650
  /* THE CRAFT MODE LOOKS (task 1004495; direction docs/design/craft-mode-direction.md).
@@ -1601,37 +1654,30 @@ html.setup-gate-open { overflow: hidden; }
1601
1654
  what to press: the accent stays the action colour in every mode. Light values
1602
1655
  clear 5.4:1 on the hall's paper; the dark values are the prototype's. Light
1603
1656
  keeps the paper ground; only dark changes the ground and the glass. */
1604
- html[data-craft="artistry"] { --craft: #2e3c6e; --craft-on: #f1e6d2; }
1605
- html[data-craft="ideating"] { --craft: #7a5a0c; --craft-on: #fdf6dd; }
1606
- html[data-craft="governing"] { --craft: #33479e; --craft-on: #eef1ff; }
1607
- html[data-theme="dark"][data-craft="artistry"] {
1657
+ html[data-craft="artist"] { --craft: #2e3c6e; --craft-on: #f1e6d2; }
1658
+ html[data-craft="patron"] { --craft: #33479e; --craft-on: #eef1ff; }
1659
+ html[data-theme="dark"][data-craft="artist"] {
1608
1660
  --craft: #f1e6d2; --craft-on: #0c1122;
1609
1661
  --bg: #07080d; --bg-frame: #0a0b12;
1610
1662
  --glass: rgba(150, 170, 230, .11); --glass-strong: rgba(170, 190, 240, .17);
1611
1663
  --glass-edge: rgba(241, 230, 210, .16);
1612
1664
  }
1613
- html[data-theme="dark"][data-craft="ideating"] {
1614
- --craft: #f2d27a; --craft-on: #1d1604;
1615
- --bg: #05060d;
1616
- --glass: rgba(140, 150, 225, .10); --glass-strong: rgba(160, 170, 240, .16);
1617
- --glass-edge: rgba(242, 210, 122, .16);
1618
- }
1619
- html[data-theme="dark"][data-craft="governing"] {
1665
+ html[data-theme="dark"][data-craft="patron"] {
1620
1666
  --craft: #aabeff; --craft-on: #0a1030;
1621
1667
  --glass-edge: rgba(170, 190, 255, .16);
1622
1668
  }
1623
1669
  /* The shared treatment: the switch's current pill, the current tab and the top
1624
1670
  bar's hairline take the mode colour. */
1625
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .craft-switch__opt[aria-pressed="true"] {
1671
+ html:is([data-craft="artist"], [data-craft="patron"]) .craft-switch__opt[aria-pressed="true"] {
1626
1672
  background: var(--craft); color: var(--craft-on);
1627
1673
  }
1628
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .nav-item--active {
1674
+ html:is([data-craft="artist"], [data-craft="patron"]) .nav-item--active {
1629
1675
  background: color-mix(in srgb, var(--craft) 14%, transparent); color: var(--craft);
1630
1676
  }
1631
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .nav-item--active .nav-icon,
1632
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .nav-item--active .nav-item__label { color: var(--craft); }
1633
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .nav-item--active::before { background: var(--craft); }
1634
- html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing"]) .app-topbar {
1677
+ html:is([data-craft="artist"], [data-craft="patron"]) .nav-item--active .nav-icon,
1678
+ html:is([data-craft="artist"], [data-craft="patron"]) .nav-item--active .nav-item__label { color: var(--craft); }
1679
+ html:is([data-craft="artist"], [data-craft="patron"]) .nav-item--active::before { background: var(--craft); }
1680
+ html:is([data-craft="artist"], [data-craft="patron"]) .app-topbar {
1635
1681
  border-bottom-color: color-mix(in srgb, var(--craft) 30%, transparent);
1636
1682
  }
1637
1683
  /* The header mark: the mode's own words beside the page title (craft-mode.js
@@ -1735,7 +1781,7 @@ html:is([data-craft="artistry"], [data-craft="ideating"], [data-craft="governing
1735
1781
  .craft-plate .craft-art { width: calc(100% / .582); transform: scale(.582); }
1736
1782
  }
1737
1783
  /* The plate follows the theme (owner, 2026-10-03): light shows each scene's day. */
1738
- html[data-theme="light"] .craft-plate .craft-art--artistry { background: #dfe3ef; }
1784
+ html[data-theme="light"] .craft-plate .craft-art--artist { background: #dfe3ef; }
1739
1785
  html[data-theme="light"] .craft-plate .craft-art__dot--star { background: #2e3c6e; }
1740
1786
  html[data-theme="light"] .craft-plate .craft-art__moon { background: #f3c98b; box-shadow: 0 0 0 9px rgba(243, 201, 139, .28); }
1741
1787
  html[data-theme="light"] .craft-plate .craft-art__ground { background: #c3c9dc; }
@@ -1745,28 +1791,8 @@ html[data-theme="light"] .craft-plate .craft-art__dot--gold { background: #c9a23
1745
1791
  html[data-theme="light"] .craft-plate .craft-art__dot--glow { background: #b8891c; box-shadow: 0 0 10px rgba(184, 137, 28, .45); }
1746
1792
  html[data-theme="light"] .craft-plate .craft-art__dot--proto { box-shadow: inset 0 0 0 1px rgba(122, 90, 12, .6); }
1747
1793
  html[data-theme="light"] .craft-plate .craft-art__ring { box-shadow: inset 0 0 0 1px rgba(122, 90, 12, .35); }
1748
- html[data-theme="light"] .craft-plate .craft-art--governing { background: #e9ecf6; }
1794
+ html[data-theme="light"] .craft-plate .craft-art--patron { background: #e9ecf6; }
1749
1795
  html[data-theme="light"] .craft-plate .craft-art__city { filter: invert(1) hue-rotate(180deg); }
1750
- /* Ideating's star dust: a few faint fixed specks across the rail itself. */
1751
- html[data-craft="ideating"] .app-sidebar {
1752
- background-image:
1753
- radial-gradient(1px 1px at 14px 40px, rgba(242, 210, 122, .5), transparent),
1754
- radial-gradient(1px 1px at 46px 130px, rgba(242, 210, 122, .35), transparent),
1755
- radial-gradient(1.5px 1.5px at 120px 90px, rgba(242, 210, 122, .4), transparent),
1756
- radial-gradient(1px 1px at 200px 190px, rgba(242, 210, 122, .35), transparent),
1757
- radial-gradient(1px 1px at 30px 230px, rgba(242, 210, 122, .3), transparent),
1758
- radial-gradient(1.5px 1.5px at 170px 260px, rgba(242, 210, 122, .3), transparent);
1759
- background-size: 246px 280px;
1760
- }
1761
- html[data-theme="light"][data-craft="ideating"] .app-sidebar {
1762
- background-image:
1763
- radial-gradient(1px 1px at 14px 40px, rgba(184, 137, 28, .45), transparent),
1764
- radial-gradient(1px 1px at 46px 130px, rgba(184, 137, 28, .3), transparent),
1765
- radial-gradient(1.5px 1.5px at 120px 90px, rgba(184, 137, 28, .35), transparent),
1766
- radial-gradient(1px 1px at 200px 190px, rgba(184, 137, 28, .3), transparent),
1767
- radial-gradient(1px 1px at 30px 230px, rgba(184, 137, 28, .25), transparent),
1768
- radial-gradient(1.5px 1.5px at 170px 260px, rgba(184, 137, 28, .25), transparent);
1769
- }
1770
1796
 
1771
1797
  /* THE MODE TOOLS (task 1004496, craft-mode.js TOOLS): a round button beside the
1772
1798
  switch, in the mode's colour, shown only in its own mode. Artistry's palette
@@ -451,8 +451,8 @@
451
451
  // A create with no discipline the server cannot infer from the wording is
452
452
  // refused (task 1002988), so the builder names the craft here. Engineer is
453
453
  // the default, the same fallback bug routing uses (ideas/inbox.js).
454
- var craftOptions = [['engineer', 'Engineer'], ['artist', 'Artist'], ['ideator', 'Ideator'], ['ui', 'UI']].map(function (c) {
455
- return '<option value="' + c[0] + '"' + (c[0] === 'engineer' ? ' selected' : '') + '>' + c[1] + '</option>';
454
+ var craftOptions = [['artisan', 'Artisan'], ['artist', 'Artist'], ['ui', 'UI']].map(function (c) {
455
+ return '<option value="' + c[0] + '"' + (c[0] === 'artisan' ? ' selected' : '') + '>' + c[1] + '</option>';
456
456
  }).join('');
457
457
  box.innerHTML =
458
458
  '<form class="td-form" data-form="promote">'
@@ -509,7 +509,7 @@
509
509
  title: title,
510
510
  description: body + provenance,
511
511
  priority: Number(form.priority.value) || 3,
512
- discipline: (form.discipline && form.discipline.value) || 'engineer',
512
+ discipline: (form.discipline && form.discipline.value) || 'artisan',
513
513
  source: 'idea_inbox',
514
514
  source_ref: 'idea:' + idea.id,
515
515
  };
@@ -750,7 +750,8 @@
750
750
  }
751
751
 
752
752
  window.addEventListener('keydown', function (e) {
753
- if (e.key === 'Escape' && document.getElementById('deeplink-card')) clearLink();
753
+ // Spent once it closed the card (ADR 0399 §2.4 row 5, task 1005144).
754
+ if (e.key === 'Escape' && document.getElementById('deeplink-card')) { e.preventDefault(); clearLink(); }
754
755
  });
755
756
  window.addEventListener('hashchange', resolve);
756
757
 
@@ -8,7 +8,7 @@
8
8
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
9
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-03-roadmap1">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
12
12
  <!-- The record archetype (shared with idea.html) and this page's own two
13
13
  shapes. Promoted out of an inline <style> by task 1003305 — the block was
14
14
  the hall's last substantive one and sat at its hall_audit ratchet. -->
@@ -57,17 +57,17 @@
57
57
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
58
58
  time so the chrome exists before the deferred page scripts execute. -->
59
59
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
60
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
60
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
61
61
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
62
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
63
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
62
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
63
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
64
64
  <script src="/builders/hall-dialog.js"></script>
65
65
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
66
66
  <script src="/builders/palette.js" defer></script>
67
67
  <!-- task-detail.js still owns the #/idea/N and #/blocker/N deep-link overlay
68
68
  (and the #/task/N → /task/N redirect, task 751); load it here too so those
69
69
  links still resolve from this page. -->
70
- <script src="/builders/task-detail.js?v=2026-07-03-taskdetail2" defer></script>
70
+ <script src="/builders/task-detail.js?v=2026-11-10-options" defer></script>
71
71
  <script src="/builders/brand-apply.js?v=2026-06-19-r56" defer></script>
72
72
  <script src="/builders/md-reader.js" defer></script>
73
73
  <script src="/builders/hall-visual.js?v=2026-09-16-visual1" defer></script>
@@ -304,3 +304,13 @@ html[data-fullscreen="on"] .sky-stage .top { padding-right: 184px; }
304
304
  .card { max-width: 240px; }
305
305
  }
306
306
  @media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
307
+
308
+ /* task 1005148: with the visor up (html.visor-on, game mode; visor.js), the sky's own layers keep
309
+ clear of the glass, as ADR 0399 §2.3 asks of a scene's pop-ups: the top row, the composer, the
310
+ jump field and the two side panels step below the compass and the place line, and the foot and
311
+ the tour rise above the visor's corner pills. Outside game mode nothing here applies. */
312
+ html.visor-on .top { padding-top: calc(60px + env(safe-area-inset-top, 0px)); }
313
+ html.visor-on .composer, html.visor-on .jump { top: calc(116px + env(safe-area-inset-top, 0px)); }
314
+ html.visor-on .panel, html.visor-on .room { top: calc(180px + env(safe-area-inset-top, 0px)); bottom: calc(200px + env(safe-area-inset-bottom, 0px)); }
315
+ html.visor-on .foot { padding-bottom: calc(132px + env(safe-area-inset-bottom, 0px)); }
316
+ html.visor-on .tour, html.visor-on .start { bottom: calc(210px + env(safe-area-inset-bottom, 0px)); }
@@ -12,8 +12,9 @@
12
12
  links, injected into this head by the server like every hall page's
13
13
  (tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet).
14
14
  The template carried its own Google Fonts link for the same two faces. -->
15
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
16
- <link rel="stylesheet" href="/builders/thinking.css?v=2026-09-27-split">
15
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
16
+ <link rel="stylesheet" href="/builders/visor.css?v=2026-11-10-visor">
17
+ <link rel="stylesheet" href="/builders/thinking.css?v=2026-11-10-visor">
17
18
  </head>
18
19
  <!-- THE SKY (task 1004231 / sky part 3 of 5, goal 1000095; ADR 0331, ADR 0227
19
20
  §11). This page is docs/design/mocks/sky/sky.template.html — the prototype
@@ -139,11 +140,13 @@
139
140
  </div>
140
141
 
141
142
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
142
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
143
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
143
144
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
144
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
145
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
145
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
146
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
146
147
  <script src="/builders/hall-dialog.js"></script>
148
+ <!-- task 1005148: the visor (glass over the scene, game mode only; ADR 0399), after the shell and hall-dialog.js -->
149
+ <script src="/builders/visor.js?v=2026-11-10-visor"></script>
147
150
  <script src="/builders/palette.js" defer></script>
148
151
 
149
152
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -152,7 +155,7 @@
152
155
  <script src="/builders/sky-data.js?v=2026-09-30-uat1"></script>
153
156
  <script src="/builders/sky-layout.js?v=2026-09-27-split"></script>
154
157
  <script src="/builders/sky-draw.js?v=2026-09-27-split"></script>
155
- <script src="/builders/sky-interaction.js?v=2026-09-30-uat1"></script>
158
+ <script src="/builders/sky-interaction.js?v=2026-11-10-visor"></script>
156
159
  <script src="/builders/sky-panel.js?v=2026-09-30-uat1"></script>
157
160
  <script src="/builders/sky-composer.js?v=2026-09-27-split"></script>
158
161
  <script src="/builders/sky-tour.js?v=2026-09-27-split"></script>
@@ -10,7 +10,7 @@
10
10
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
11
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
13
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
14
14
  <link rel="stylesheet" href="/builders/tweak-editor.css?v=2026-09-29-tw27-aqfix">
15
15
  </head>
16
16
  <!-- THE TWEAK EDITOR (task 1004321 / BV2.TW10, goal 1000095; ADR 0341 D4 and
@@ -143,14 +143,14 @@
143
143
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
144
144
 
145
145
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
146
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
146
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
147
147
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
148
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
149
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
148
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
149
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
150
150
  <script src="/builders/hall-dialog.js"></script>
151
151
  <script src="/builders/palette.js" defer></script>
152
152
  <script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
153
153
  <script src="/builders/tweak-editor-lib.js?v=2026-09-29-tw27"></script>
154
- <script src="/builders/tweak-editor.js?v=2026-09-29-tw27-aqfix"></script>
154
+ <script src="/builders/tweak-editor.js?v=2026-11-10-options"></script>
155
155
  </body>
156
156
  </html>
@@ -647,7 +647,11 @@
647
647
  if (ev.target && ev.target.classList && ev.target.classList.contains('tw-line')) flush();
648
648
  });
649
649
  document.addEventListener('keydown', (ev) => {
650
- if (ev.key === 'Escape') { closeRefused(); setMenu(false); }
650
+ if (ev.key === 'Escape') {
651
+ // Spent only when it closed something (ADR 0399 §2.4 row 5, task 1005144).
652
+ if (!$('tw-refused').hidden || $('tw-openwrap').classList.contains('is-open')) ev.preventDefault();
653
+ closeRefused(); setMenu(false);
654
+ }
651
655
  if (ev.target && ev.target.id === 'tw-divider') {
652
656
  const next = lib.splitFromKey(st.splitSize, ev.key);
653
657
  if (next !== null) { ev.preventDefault(); setSize(next); remember(SIZE_KEY, String(st.splitSize)); }
@@ -38,6 +38,8 @@
38
38
  'use strict';
39
39
 
40
40
  var RUN_KEY = 'bongos.update.run';
41
+ var LATER_KEY = 'bongos.update.later';
42
+ var LATER_MS = 24 * 60 * 60 * 1000;
41
43
  var MSG = 'bongos-update'; // the tag deploy-handoff.js answers to; both sides check it
42
44
  var VERSION_RE = /^\d+\.\d+\.\d+$/;
43
45
  // A hub door as the server words it (core-update.js updateDoor): an origin and
@@ -152,12 +154,34 @@
152
154
  return slow ? 'slow' : 'starting';
153
155
  }
154
156
 
157
+ // THE POP-UP (task 1005191). The owner, 2026-11-10: the pill alone was not seen. Game mode
158
+ // opens every page without its bars, and a project sat 3 minor versions behind. So an
159
+ // update that is ready also ASKS, once, in the hall's own dialog. Any way of closing it
160
+ // other than Update now is "later": that version is not asked about again in this browser
161
+ // for a day. The pill stays, so later never means lost.
162
+ function readLater(storage) {
163
+ var l = null;
164
+ try { l = JSON.parse((storage && storage.getItem(LATER_KEY)) || 'null'); } catch (e) { l = null; }
165
+ return l && isVersion(l.v) && isFinite(l.at) ? l : null;
166
+ }
167
+ function keepLater(storage, version, now) {
168
+ try { if (storage && isVersion(version)) storage.setItem(LATER_KEY, JSON.stringify({ v: version, at: now })); } catch (e) { /* it asks again next page */ }
169
+ }
170
+ /** Whether the pop-up opens: only for an update that is ready, and not for a version the
171
+ * owner already said "later" to inside the last day. A newer version asks again at once. */
172
+ function askDue(o) {
173
+ if (!o || o.face !== 'ready' || !isVersion(o.offered)) return false;
174
+ var l = o.later;
175
+ if (l && l.v === o.offered && o.now >= l.at && o.now - l.at < LATER_MS) return false;
176
+ return true;
177
+ }
178
+
155
179
  // ---------- the page half ----------
156
180
 
157
181
  var state = {
158
182
  api: null, update: null, held: null, sw: null, swAsked: null, swError: null, ended: null, note: null,
159
183
  face: 'none', stage: null, run: null, error: null, pill: null, card: null,
160
- popup: null, plan: null, offered: null, looks: 0, timer: null, popupTimer: null, listening: false,
184
+ popup: null, plan: null, offered: null, asked: false, looks: 0, timer: null, popupTimer: null, listening: false,
161
185
  };
162
186
 
163
187
  function doc() { return root && root.document; }
@@ -316,7 +340,7 @@
316
340
  d.body.appendChild(c);
317
341
  state.card = c;
318
342
  if (root.addEventListener) root.addEventListener('resize', function () { if (state.card && !state.card.hidden) placeCard(); });
319
- d.addEventListener('keydown', function (e) { if (e.key === 'Escape' && state.card && !state.card.hidden) { closeCard(); if (state.pill) state.pill.focus(); } });
343
+ d.addEventListener('keydown', function (e) { if (e.key === 'Escape' && state.card && !state.card.hidden) { e.preventDefault(); closeCard(); if (state.pill) state.pill.focus(); } }); // spent: ADR 0399 §2.4, task 1005144
320
344
  d.addEventListener('click', function (e) {
321
345
  if (!state.card || state.card.hidden) return;
322
346
  var t = e.target;
@@ -556,6 +580,69 @@
556
580
  if (root.location && root.location.reload) root.location.reload();
557
581
  }
558
582
 
583
+ // ---------- the pop-up ----------
584
+
585
+ // Not in the hub's handoff window, not on the update door itself, and not over the setup
586
+ // screen: each of those is already the thing the owner is doing.
587
+ function askAllowed() {
588
+ var d = doc();
589
+ if (!d || !root.OTBDialog || typeof root.OTBDialog.open !== 'function' || state.asked) return false;
590
+ var el = d.documentElement;
591
+ if (el && el.dataset && el.dataset.handoff === 'on') return false;
592
+ if (root.OTBSetupGate) return false;
593
+ return !(root.location && root.location.pathname === '/deploy');
594
+ }
595
+
596
+ function askBodyHtml(plan) {
597
+ var u = state.update || {};
598
+ var h = highlights((state.sw.update || {}).whats_new, HIGHLIGHTS);
599
+ var list = h.lines.length ? '<ul class="upd-card__list">' + h.lines.map(function (l) { return '<li>' + esc(l) + '</li>'; }).join('') + '</ul>' : '';
600
+ var note = plan.kind === 'cli'
601
+ ? 'This project is updated on the server that runs it: <code>bongos upgrade</code> there takes this version, and puts the old one back if it fails.'
602
+ : 'Takes a few minutes. The project restarts once, and goes back to the version it runs now on its own if the new one is not healthy.';
603
+ var versions = isVersion(u.running) && isVersion(state.offered) ? '<p class="upd-card__ver">' + mono(u.running) + ' → ' + mono(state.offered) + '</p>' : '';
604
+ return '<p>A newer version of Bongos is ready, with the latest changes and bug fixes.</p>' + list +
605
+ '<p class="upd-card__note">' + note + '</p>' + versions;
606
+ }
607
+
608
+ // Asked from the same reading the card uses, so the pop-up and the card name one version
609
+ // and the two-step rule holds: the pop-up shows the version, Update now sends that one.
610
+ function maybeAsk() {
611
+ if (!askAllowed() || !askDue({ face: state.face, offered: state.offered, later: readLater(store()), now: now() })) return;
612
+ var read = readSoftwareUpdate();
613
+ if (!read) { ask(); return; }
614
+ read.then(ask);
615
+ }
616
+ function ask() {
617
+ if (!state.sw || !askAllowed() || !askDue({ face: state.face, offered: state.offered, later: readLater(store()), now: now() })) return;
618
+ var plan = doorPlan(state.sw);
619
+ if (plan.kind === 'none') return; // a viewer the door would refuse is not asked
620
+ var d = doc();
621
+ var body = d.createElement('div');
622
+ body.className = 'upd-ask';
623
+ body.innerHTML = askBodyHtml(plan);
624
+ var canGo = plan.kind === 'local' || plan.kind === 'hub';
625
+ var offered = state.offered;
626
+ var actions = canGo
627
+ ? [{ label: 'Later', value: 'later', kind: 'ghost' }, { label: 'Update now', value: 'go' }]
628
+ : [{ label: 'Close', value: 'later', kind: 'ghost' }];
629
+ state.asked = true;
630
+ var dlg = root.OTBDialog.open({ title: 'Update the builders hall?', body: body, actions: actions, initialFocus: '[data-dialog-value="' + (actions.length - 1) + '"]' });
631
+ // Update now runs inside the press itself: a hosted project opens the hub's window, and
632
+ // a browser allows that only from the click, not from the dialog's settled promise.
633
+ if (canGo && dlg && dlg.el && dlg.el.addEventListener) {
634
+ dlg.el.addEventListener('click', function (e) {
635
+ var t = e && e.target;
636
+ var b = t && t.closest ? t.closest('[data-dialog-value]') : null;
637
+ if (!b || b.getAttribute('data-dialog-value') !== '1') return;
638
+ if (updateNow()) openCard();
639
+ });
640
+ }
641
+ if (dlg && dlg.result && dlg.result.then) {
642
+ dlg.result.then(function (v) { if (v !== 'go') keepLater(store(), offered, now()); });
643
+ }
644
+ }
645
+
559
646
  /** shell.js hands over GET /core-update's answer; the pill decides what, if anything, to show. */
560
647
  function mount(data, opts) {
561
648
  state.api = opts && opts.api;
@@ -575,6 +662,7 @@
575
662
  state.face = face;
576
663
  drawPill();
577
664
  if (face === 'running') schedule();
665
+ if (face === 'ready') maybeAsk();
578
666
  return face;
579
667
  }
580
668
 
@@ -590,6 +678,7 @@
590
678
  // the pure half, for the tests
591
679
  highlights: highlights, doorPlan: doorPlan, pillState: pillState, stageOf: stageOf,
592
680
  readRun: readRun, keepRun: keepRun, forgetRun: forgetRun, isVersion: isVersion,
681
+ askDue: askDue, readLater: readLater, keepLater: keepLater, LATER_KEY: LATER_KEY, LATER_MS: LATER_MS,
593
682
  RUN_KEY: RUN_KEY, MSG: MSG, SLOW_MS: SLOW_MS, GIVE_UP_MS: GIVE_UP_MS,
594
683
  _state: state,
595
684
  };