@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
@@ -30,7 +30,7 @@
30
30
  (function () {
31
31
  'use strict';
32
32
 
33
- const CRAFT_WORD = Object.freeze({ engineer: 'Engineer', artist: 'Artist', ideator: 'Ideator' });
33
+ const CRAFT_WORD = Object.freeze({ artisan: 'Artisan', artist: 'Artist' });
34
34
  const DASH = '—';
35
35
 
36
36
  function count(n) {
@@ -44,7 +44,7 @@
44
44
  // existed reads as the engineer it always rendered.
45
45
  function craftsOf(roles) {
46
46
  const shown = roles && Array.isArray(roles.shown) ? roles.shown.filter((c) => CRAFT_WORD[c]) : [];
47
- return shown.length ? shown : ['engineer'];
47
+ return shown.length ? shown : ['artisan'];
48
48
  }
49
49
 
50
50
  function makeNum(fmt) {
@@ -78,39 +78,43 @@
78
78
  const main = crafts[0];
79
79
  const shipped = Number(d.shipped_count) || 0;
80
80
  const artist = (roles && roles.artist) || {};
81
- const ideator = (roles && roles.ideator) || {};
81
+ const ideator = (roles && roles.artist) || {};
82
82
  const achievements = Array.isArray(d.achievements) ? d.achievements.length : 0;
83
83
  const credits = { n: num(count(Number(builder.total_credits))), w: cur, lead: true };
84
84
  const weekGain = (n) => (count(n) == null ? DASH : `+${fmt(n)}`);
85
85
 
86
86
  // The tally: the person's total, then the two numbers their main craft leads with.
87
87
  const LEAD = {
88
- engineer: () => [{ n: num(shipped), w: plural(shipped, 'work shipped', 'works shipped') },
88
+ artisan: () => [{ n: num(shipped), w: plural(shipped, 'work shipped', 'works shipped') },
89
89
  { n: num(count(Number(builder.karma))), w: 'karma' }],
90
- artist: () => [{ n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved') },
91
- { n: weekGain(artist.this_week), w: 'this week' }],
92
- ideator: () => [{ n: num(ideator.filed), w: plural(ideator.filed, 'thought filed', 'thoughts filed') },
93
- { n: num(ideator.ignited), w: 'ignited' }],
90
+ // The artist craft holds the old ideator's work too (task 1005141), so its
91
+ // lead is one number from each half: pages approved, thoughts filed.
92
+ // An artist with ideas and no approved page leads with the ideas, so the
93
+ // first thing a visitor reads is never a zero that is not their work. (An
94
+ // UNKNOWN page count still leads with its dash: that is a fact about the instance.)
95
+ artist: () => (count(artist.pages_approved) === 0 && count(artist.filed) > 0
96
+ ? [{ n: num(artist.filed), w: plural(artist.filed, 'thought filed', 'thoughts filed') },
97
+ { n: num(artist.ignited), w: 'ignited' }]
98
+ : [{ n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved') },
99
+ { n: num(artist.filed), w: plural(artist.filed, 'thought filed', 'thoughts filed') }]),
94
100
  };
95
101
 
96
102
  // The main craft's full set of tiles.
97
103
  const surfacesWord = (n) => (count(n) == null ? '' : `${fmt(n)} ${plural(n, 'surface', 'surfaces')}`);
98
104
  const MAIN = {
99
- engineer: () => [
105
+ artisan: () => [
100
106
  { n: num(shipped), w: plural(shipped, 'work shipped', 'works shipped') },
101
107
  { n: num(count(Number(builder.total_credits))), w: cur, f: 'all kinds, see below' },
102
108
  { n: num(count(Number(builder.karma))), w: 'karma' },
103
109
  { n: num(achievements), w: plural(achievements, 'achievement', 'achievements'), f: 'earned' },
104
110
  ],
105
- artist: () => [
106
- { n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved'), f: surfacesWord(artist.surfaces_touched) },
107
- { n: num(artist.credits), w: `${cur} from pages` },
108
- { n: weekGain(artist.this_week), w: 'this week' },
109
- ],
110
- ideator: () => {
111
+ artist: () => {
111
112
  const size = ideator.size || {};
112
113
  const ratified = count(ideator.ratified);
113
114
  return [
115
+ { n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved'), f: surfacesWord(artist.surfaces_touched) },
116
+ { n: weekGain(artist.this_week), w: 'this week' },
117
+ { n: num(artist.credits), w: cur, f: 'pages and ideas' },
114
118
  { n: num(ideator.filed), w: plural(ideator.filed, 'thought filed', 'thoughts filed') },
115
119
  { n: num(ideator.ignited), w: 'ignited', f: 'became work' },
116
120
  { n: num(ideator.full_ideas), w: plural(ideator.full_ideas, 'Full Idea', 'Full Ideas'), f: ratified == null ? '' : `${fmt(ratified)} ratified by the board` },
@@ -128,16 +132,16 @@
128
132
  // Each OTHER craft a person has earned in gets its one headline tile, after
129
133
  // the main craft's, in the order the server put them.
130
134
  const SECOND = {
131
- engineer: () => ({ n: num(shipped), w: plural(shipped, 'work shipped', 'works shipped') }),
132
- artist: () => ({ n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved'), f: surfacesWord(artist.surfaces_touched) }),
133
- ideator: () => ({ n: num(ideator.filed), w: plural(ideator.filed, 'thought filed', 'thoughts filed'), f: count(ideator.ignited) == null ? '' : `${fmt(ideator.ignited)} ignited` }),
135
+ artisan: () => ({ n: num(shipped), w: plural(shipped, 'work shipped', 'works shipped') }),
136
+ artist: () => ({ n: num(artist.pages_approved), w: plural(artist.pages_approved, 'page approved', 'pages approved'),
137
+ f: count(artist.filed) == null ? surfacesWord(artist.surfaces_touched) : `${fmt(artist.filed)} ${plural(artist.filed, 'thought', 'thoughts')} filed` }),
134
138
  };
135
139
 
136
140
  const tiles = MAIN[main]().concat(crafts.slice(1).map((c) => SECOND[c]()));
137
141
  // Karma is on every profile (the owner, 2026-10-01, reviewing this build:
138
142
  // "karma for artists and ideators is definitely key"). The engineer's set
139
143
  // already carries it; every other main craft ends with it.
140
- if (main !== 'engineer') tiles.push({ n: num(count(Number(builder.karma))), w: 'karma' });
144
+ if (main !== 'artisan') tiles.push({ n: num(count(Number(builder.karma))), w: 'karma' });
141
145
 
142
146
  // The artist leads with the studio's "N of M tweaked", one row per surface.
143
147
  const surfaces = main === 'artist' && Array.isArray(artist.surfaces)
@@ -223,7 +223,7 @@
223
223
  the day each thought was filed (the approved mock's .trail and .m-*). Size is
224
224
  a mark's diameter and brightness a star's opacity; the words are the sky's.
225
225
  A mark and its ledger row light together (.is-hot), the sky's rule. */
226
- #activity-ideator-panel {
226
+ #activity-ideas-panel {
227
227
  --pt-soft: color-mix(in srgb, var(--ink) 52%, transparent);
228
228
  --pt-faint: color-mix(in srgb, var(--ink) 22%, transparent);
229
229
  --pt-cold: color-mix(in srgb, var(--ink) 8%, var(--bg-card));
@@ -14,7 +14,7 @@
14
14
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
15
15
  <link rel="preconnect" href="https://fonts.googleapis.com">
16
16
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
17
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
18
18
  <!-- The PANEL archetype (task 1003308) before the page's own sheet. -->
19
19
  <link rel="stylesheet" href="/builders/panel.css">
20
20
  <link rel="stylesheet" href="/builders/hall-ask.css">
@@ -57,9 +57,9 @@
57
57
  </section>
58
58
 
59
59
  <!-- By the numbers — led by the person's own craft (task 1004434):
60
- works shipped for an engineer, pages approved and the per-surface
60
+ works shipped for an artisan, pages approved and the per-surface
61
61
  "N of M tweaked" for an artist, thoughts, size and what is still
62
- alive for an ideator. profile-roles.js says what; profile.js draws. -->
62
+ alive for an artist's ideas. profile-roles.js says what; profile.js draws. -->
63
63
  <section class="scroll" id="numbers-scroll" aria-labelledby="numbers-h" data-group="overview">
64
64
  <h2 id="numbers-h" class="scroll__h">By the numbers</h2>
65
65
  <div id="numbers-body">
@@ -142,7 +142,7 @@
142
142
  <!-- One tab per role the person has (task 1004435): their main role
143
143
  and every other role that has earned credits, as the header's
144
144
  chips are. Each tab is its craft's own record. -->
145
- <div id="activity-engineer-panel" hidden>
145
+ <div id="activity-artisan-panel" hidden>
146
146
  <div id="activity-tasks-panel">
147
147
  <h3 class="profile-act__h">Works completed</h3>
148
148
  <div id="activity-tasks"></div>
@@ -154,22 +154,23 @@
154
154
  </div>
155
155
  </div>
156
156
 
157
- <!-- The ideator's trail: the room's public trail (the sky's five
158
- states, size and brightness), every drawn thought also a row.
159
- It folds in the old "Ideas filed" list. -->
160
- <div id="activity-ideator-panel" hidden>
161
- <p class="scroll__lede" id="trail-lede"></p>
162
- <div class="pt-trail" id="trail-figure"></div>
163
- <div id="trail-legend"></div>
164
- <div id="activity-ideas"></div>
165
- <p class="pt-foot" id="trail-foot" hidden></p>
166
- </div>
167
-
168
157
  <!-- The artist's approved pages, each with a small before/after. -->
169
158
  <div id="activity-artist-panel" hidden>
170
159
  <p class="scroll__lede" id="pages-lede"></p>
171
160
  <ul class="pgs" id="activity-pages"></ul>
172
161
  <div id="pages-more"></div>
162
+
163
+ <!-- The artist's ideas: the ideator's trail before the two crafts
164
+ folded (task 1005141) — the room's public trail (the sky's five
165
+ states, size and brightness), every drawn thought also a row. -->
166
+ <div id="activity-ideas-panel">
167
+ <h3 class="profile-act__h">Ideas</h3>
168
+ <p class="scroll__lede" id="trail-lede"></p>
169
+ <div class="pt-trail" id="trail-figure"></div>
170
+ <div id="trail-legend"></div>
171
+ <div id="activity-ideas"></div>
172
+ <p class="pt-foot" id="trail-foot" hidden></p>
173
+ </div>
173
174
  </div>
174
175
  </div>
175
176
  </section>
@@ -247,10 +248,10 @@
247
248
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
248
249
  chrome exists before the page script runs. -->
249
250
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
250
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
251
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
251
252
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
252
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
253
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
253
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
254
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
254
255
  <script src="/builders/hall-dialog.js"></script>
255
256
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
256
257
  <script src="/builders/palette.js" defer></script>
@@ -338,13 +338,14 @@
338
338
  function xpCraftTiles(crafts) {
339
339
  if (!crafts || typeof crafts !== 'object') return '';
340
340
  const out = [];
341
+ // One artist block since the ideator folded in (task 1005141): its pages
342
+ // half, then its ideas half.
341
343
  const artist = crafts.artist;
342
- if (artist && typeof artist === 'object') out.push(tile('Pages approved', xpCount(artist.pages_approved), 'as an artist'));
343
- const ideator = crafts.ideator;
344
- if (ideator && typeof ideator === 'object') {
345
- out.push(tile('Thoughts filed', xpCount(ideator.filed), 'as an ideator'));
346
- const ratified = Number.isInteger(ideator.ratified) ? `${fmtNum(ideator.ratified)} ratified by the board` : '';
347
- out.push(tile('Full Ideas', xpCount(ideator.full_ideas), ratified));
344
+ if (artist && typeof artist === 'object') {
345
+ out.push(tile('Pages approved', xpCount(artist.pages_approved), 'as an artist'));
346
+ out.push(tile('Thoughts filed', xpCount(artist.filed), 'as an artist'));
347
+ const ratified = Number.isInteger(artist.ratified) ? `${fmtNum(artist.ratified)} ratified by the board` : '';
348
+ out.push(tile('Full Ideas', xpCount(artist.full_ideas), ratified));
348
349
  }
349
350
  return out.length ? `<div class="stat-row stat-row--craft">${out.join('')}</div>` : '';
350
351
  }
@@ -431,11 +432,11 @@
431
432
  // record, never "tasks that happen to carry its label":
432
433
  // engineer the works they completed and the goals they created, every
433
434
  // craft of task included (most of the corpus is 'unclassified',
434
- // and a filter to 'engineer' would read as "you did less")
435
+ // and a filter to 'artisan' would read as "you did less")
435
436
  // artist the pages they rewrote in Tweak Mode that were approved
436
437
  // ideator the room's public trail: every thought they filed, in the sky's
437
438
  // five states, drawn and listed (the old idea trail, folded in)
438
- const ROLE_TAB_WORD = { engineer: 'Engineer', artist: 'Artist', ideator: 'Ideator' };
439
+ const ROLE_TAB_WORD = { artisan: 'Artisan', artist: 'Artist' };
439
440
 
440
441
  // Every href below goes through BOTH encodings, and it needs both: the ids are
441
442
  // DB integers today, but encodeURIComponent leaves a literal `'` alone, so on
@@ -670,7 +671,7 @@
670
671
  },
671
672
  });
672
673
 
673
- // ---- the ideator: the room's public trail (task 1004435) ----------------
674
+ // ---- the artist: the room's public trail (task 1004435) ----------------
674
675
  // ONE read of up to the route's cap, drawn whole and listed under the
675
676
  // drawing, so every mark has its row and every row its mark (the sky's
676
677
  // accessibility rule). The ledger pages that list in the browser; past the
@@ -692,7 +693,7 @@
692
693
  trailLoaded = true;
693
694
  const first = String(ownerName || 'This builder').split(' ')[0];
694
695
  const lede = $('#trail-lede');
695
- if (lede) lede.textContent = crafts.thoughtsLede(first, mainRole === 'ideator');
696
+ if (lede) lede.textContent = crafts.thoughtsLede(first, mainRole === 'artist');
696
697
  try {
697
698
  const res = await api.request('GET', `${API}/inbox/by-builder/${encodeURIComponent(builderId)}?limit=${TRAIL_CAP}&offset=0`);
698
699
  if (!res.ok) throw new Error(`idea trail → ${res.status}`);
@@ -795,15 +796,16 @@
795
796
  // ---- the tabs ---------------------------------------------------------------
796
797
  // One panel per role tab, so makeTabs' own panel toggle does the showing; a
797
798
  // tab's record loads the first time it is opened.
798
- const shownRoles = (roleTabs && roleTabs.length ? roleTabs : ['engineer']).filter((c) => ROLE_TAB_WORD[c]);
799
+ const shownRoles = (roleTabs && roleTabs.length ? roleTabs : ['artisan']).filter((c) => ROLE_TAB_WORD[c]);
799
800
  const loaded = new Set();
800
801
  function load(id) {
801
- if (id === 'engineer') {
802
+ if (id === 'artisan') {
802
803
  [tasks, goals].forEach((l) => { if (l) { l.reset(); l.load(); } });
803
- } else if (id === 'ideator') {
804
+ } else if (id === 'artist') {
805
+ // One tab since the ideator folded into the artist (task 1005141): the
806
+ // approved pages, then the ideas trail under them.
807
+ if (!loaded.has(id)) loadPages(false);
804
808
  loadTrail();
805
- } else if (id === 'artist' && !loaded.has(id)) {
806
- loadPages(false);
807
809
  }
808
810
  loaded.add(id);
809
811
  }
@@ -824,7 +826,7 @@
824
826
  const section = $('#activity-scroll');
825
827
  const placeholder = $('#activity-placeholder');
826
828
  if (!section) return;
827
- const PANELS = ['activity-engineer-panel', 'activity-artist-panel', 'activity-ideator-panel'];
829
+ const PANELS = ['activity-artisan-panel', 'activity-artist-panel'];
828
830
  if (!signedIn) {
829
831
  // Owner decision (a), 2026-09-30: "no one should be able to open up the
830
832
  // hood of data without being signed in." The identity band, the tally and
@@ -964,9 +966,8 @@
964
966
  main: view.crafts[0].craft,
965
967
  roles: view.crafts.map((c) => c.craft),
966
968
  counts: {
967
- engineer: Number(data.shipped_count) || 0,
969
+ artisan: Number(data.shipped_count) || 0,
968
970
  artist: r.artist && Number.isFinite(r.artist.pages_approved) ? r.artist.pages_approved : null,
969
- ideator: r.ideator && Number.isFinite(r.ideator.filed) ? r.ideator.filed : null,
970
971
  },
971
972
  });
972
973
  // Connections (section 6, task 1002296) — a separate hub-only script that
@@ -110,8 +110,8 @@
110
110
  ]
111
111
  }
112
112
  },
113
- "activity-ideator": {
114
- "_": "The ideator's Activity tab (task 1004435): the room's public trail, every mark also a row. Fixtures builders__2002__profile + inbox__by-builder__2002.",
113
+ "activity-artist-ideas": {
114
+ "_": "The Artist tab of a builder whose artist work is ideas (task 1004435; one Artist tab since task 1005141): the room's public trail, every mark also a row. Fixtures builders__2002__profile + inbox__by-builder__2002.",
115
115
  "auth": true,
116
116
  "url": "/profile?id=2002#activity",
117
117
  "actions": [
@@ -164,8 +164,8 @@
164
164
  ]
165
165
  }
166
166
  },
167
- "ideator": {
168
- "_": "An ideator who has never shipped a task (task 1004434): thoughts filed, ignited, Full Ideas, total size with its historical-estimate mark, and what is still alive. Fixture builders__2002__profile. Since task 1004436 the earnings figure draws for them too, every credit from an idea stream, from builders__2002__earnings beside an empty builders__2002__activity.",
167
+ "artist-ideas": {
168
+ "_": "An artist with ideas and no approved page (task 1004434; the ideator folded into the artist in task 1005141): the header leads with thoughts filed, then ignited, Full Ideas, total size with its historical-estimate mark, and what is still alive. Fixture builders__2002__profile. Since task 1004436 the earnings figure draws for them too, every credit from an idea stream, from builders__2002__earnings beside an empty builders__2002__activity.",
169
169
  "auth": true,
170
170
  "url": "/profile?id=2002",
171
171
  "actions": [
@@ -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-02-shell1">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
12
12
  <link rel="stylesheet" href="/builders/oversight.css">
13
13
  <link rel="stylesheet" href="/builders/project-settings.css?v=2026-11-02-outflow">
14
14
  </head>
@@ -75,10 +75,10 @@
75
75
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
76
76
 
77
77
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
78
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
78
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
79
79
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
80
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
81
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
80
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
81
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
82
82
  <script src="/builders/hall-dialog.js"></script>
83
83
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
84
84
  <script src="/builders/palette.js" defer></script>
@@ -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-02-shell1">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
12
12
  <!-- task 1003441: the identity cell (avatar, name, login). It was shared with
13
13
  the cross-project /people page until task 1003444 deleted it. -->
14
14
  <link rel="stylesheet" href="/builders/roster.css">
@@ -57,10 +57,10 @@
57
57
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
58
58
  chrome exists before the page script runs. -->
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>
@@ -114,9 +114,9 @@
114
114
  // split. Owner decision (b): a column naming them AND the role toggle above,
115
115
  // which ranks by the credits earned in that craft. The figure a role ranks by
116
116
  // is in the row (ADR 0255: a public list is ordered only by what it publishes).
117
- var CRAFTS = ['engineer', 'artist', 'ideator'];
118
- var CRAFT_WORD = { engineer: 'Engineer', artist: 'Artist', ideator: 'Ideator' };
119
- var ROLE_CHIPS = [['', 'Everyone'], ['engineer', 'Engineers'], ['artist', 'Artists'], ['ideator', 'Ideators']];
117
+ var CRAFTS = ['artisan', 'artist'];
118
+ var CRAFT_WORD = { artisan: 'Artisan', artist: 'Artist' };
119
+ var ROLE_CHIPS = [['', 'Everyone'], ['artisan', 'Artisans'], ['artist', 'Artists']];
120
120
  function shownOf(b) { return (b.roles && Array.isArray(b.roles.shown)) ? b.roles.shown : []; }
121
121
  function craftCredits(b, craft) {
122
122
  var by = b.roles && b.roles.credits_by_craft;
@@ -28,12 +28,31 @@
28
28
  .settings-groups[data-active="update"] > [data-group="update"],
29
29
  .settings-groups[data-active="extensions"] > [data-group="extensions"] { display: block; }
30
30
  .settings-groups > [data-group][hidden] { display: none !important; }
31
+ /* A screen opened in the menu's frame (options-menu.js): one shows at a time. */
32
+ .settings-groups > .opt-embed.opt-embed--on { display: block; }
31
33
  .settings-groups .scroll { margin: 0 0 var(--sp-sm); }
32
34
  .settings-groups .scroll__lede { font-size: 14.5px; }
33
35
  /* the rail's items at the mock's height: the shell's 28px rows are Standing's
34
36
  density, and a settings group is a destination, not a scroll-spy stop */
35
- #settings-rail .rail-link { min-height: 38px; padding: 0 14px; font-size: 14.5px; text-transform: none; border-radius: var(--radius-pill); }
36
- #settings-rail .rail-link--active::before { left: 0; top: 7px; bottom: 7px; }
37
+ /* ---- the options menu rail (task 1005144, ADR 0401) ------------------------
38
+ A search box over a vertical list of groups. Sticky beside the open screen, so
39
+ the menu stays in reach while a long screen scrolls. */
40
+ .opt-rail { position: sticky; top: 72px; display: flex; flex-direction: column; gap: 2px; max-height: calc(100vh - 96px); overflow-y: auto; }
41
+ html[data-fullscreen="on"] .opt-rail { top: 24px; max-height: calc(100vh - 48px); }
42
+ .opt-search { display: block; margin: 0 0 var(--sp-xs); }
43
+ .opt-search input { width: 100%; min-height: 38px; padding: 0 14px; border-radius: var(--radius-pill); border: var(--line) solid var(--glass-edge); background: var(--glass); color: var(--ink); font: inherit; font-size: var(--ds-text-md); }
44
+ .opt-search input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
45
+ .opt-head { margin: var(--sp-sm) 0 2px; padding: 0 14px; font-family: var(--label-face); font-size: var(--label-size); letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
46
+ .opt-link { position: relative; display: flex; flex-direction: column; justify-content: center; min-height: 38px; padding: 4px 14px; border-radius: var(--radius-pill); color: var(--ink-soft); font-size: var(--ds-text-md); text-decoration: none; }
47
+ .opt-link:hover { color: var(--ink); background: var(--glass); }
48
+ .opt-link:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
49
+ .opt-link--active { color: var(--ink); background: var(--glass); }
50
+ .opt-link--active::before { content: ""; position: absolute; left: 0; top: 9px; bottom: 9px; width: 3px; border-radius: var(--radius-pill); background: var(--accent); }
51
+ .opt-link__where { font-size: var(--ds-text-xs); color: var(--ink-faint); }
52
+ .opt-none { margin: var(--sp-xs) 0; padding: 0 14px; font-size: var(--ds-text-sm-plus); color: var(--ink-soft); }
53
+ /* The frame fills the column to the bottom of the window; the screen in it scrolls itself. */
54
+ .opt-embed__frame { display: block; width: 100%; height: calc(100vh - 96px); min-height: 480px; border: 0; border-radius: var(--radius); background: transparent; }
55
+ html[data-fullscreen="on"] .opt-embed__frame { height: calc(100vh - 48px); }
37
56
 
38
57
  /* the group head: the group's name in the display voice over a hairline, with
39
58
  its own address in the mono face beside it (a machine's word keeps its case) */
@@ -50,9 +69,10 @@
50
69
  .grp__eyebrow { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0; text-transform: none; color: var(--ink-faint); }
51
70
 
52
71
  @media (max-width: 860px) {
53
- /* Collapse to one column; the shared .section-rail ≤768px rules turn the
54
- rail into a horizontal chip strip just under the top bar. */
72
+ /* Collapse to one column: the menu sits above the open screen, no longer sticky. */
55
73
  .settings-layout { grid-template-columns: minmax(0, 1fr); gap: var(--sp-md); }
74
+ .opt-rail { position: static; max-height: none; }
75
+ .opt-embed__frame { height: 80vh; }
56
76
  }
57
77
  @media (max-width: 520px) {
58
78
  .grp__head { flex-direction: column; align-items: flex-start; gap: 4px; }
@@ -3,15 +3,15 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Settings — {{worldName}}</title>
7
- <meta name="description" content="Your preferences — connections, access keys, and sounds.">
6
+ <title>Options — {{worldName}}</title>
7
+ <meta name="description" content="Every setting in one menu: your account, your agents, keys and sound, and the project's own settings, modules and permissions.">
8
8
  <!-- the hub's origin, stamped server-side (task 1004259): the Profile and
9
9
  privacy row links to its account page. Empty on an instance with no hub. -->
10
10
  <meta name="hub-origin" content="{{hubOrigin}}">
11
11
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
12
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
13
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
- <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
14
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-10-options">
15
15
  <!-- The PANEL archetype (task 1003308): the row, the switch, the field, the
16
16
  chip control and the family's voices, shared with profile and pair.
17
17
  settings.css then holds only what this page
@@ -21,7 +21,7 @@
21
21
  <!-- task 1005094: the device cards and their Run button in Your Autobongos runner. -->
22
22
  <link rel="stylesheet" href="/builders/runner-button.css">
23
23
  </head>
24
- <body data-page="settings" data-page-title="Settings">
24
+ <body data-page="settings" data-page-title="Options">
25
25
 
26
26
  <div class="app">
27
27
  <aside class="app-sidebar" id="app-sidebar" aria-label="Primary"></aside>
@@ -33,7 +33,7 @@
33
33
  room voice, because here the document is the page. The sub-line is
34
34
  settings.js's — "Your preferences, <name>." and the two failure states. -->
35
35
  <div class="page-head page-head--room page-head--panel">
36
- <h1 id="settings-h1" class="page-head__h">settings</h1>
36
+ <h1 id="settings-h1" class="page-head__h">options</h1>
37
37
  <p class="page-head__sub" id="settings-sub">Loading your preferences…</p>
38
38
  </div>
39
39
 
@@ -47,13 +47,15 @@
47
47
  <div class="row-end"><a class="pbtn pbtn--save" href="/api/bongos/auth/web/start">Sign in</a></div>
48
48
  </section>
49
49
 
50
- <!-- Grouped layout (task 1723 → kit, task 2172): the sections sit in six
51
- groups behind a left sub-nav rail built by OTBKit.makeSectionRail
52
- (switch mode). settings.js wires the rail + per-panel anchor deep
53
- links (/settings#cli, /settings#art-key, …); only the active group's
54
- sections display. -->
50
+ <!-- The ONE options menu (task 1005144, ADR 0401; before it task 1723 → 2172):
51
+ the rail is a search box over every setting, grouped. Settings' own
52
+ sections sit in groups here; the screens that used to be pages (My
53
+ agents, Project settings, Modules, Permissions, Market Watch) open in a
54
+ frame that options-menu.js appends to #settings-groups. Per-panel
55
+ anchors (/settings#cli, /settings#art-key, …) still land; only the
56
+ active group's sections display. -->
55
57
  <div class="settings-layout" id="settings-layout">
56
- <nav class="section-rail" id="settings-rail" aria-label="Settings sections"></nav>
58
+ <nav class="opt-rail" id="settings-rail" aria-label="Options"></nav>
57
59
 
58
60
  <div class="settings-groups" id="settings-groups" data-active="account">
59
61
  <!-- task 1005043: the panel loader, until settings.js has read who is viewing (hideLayout). -->
@@ -403,10 +405,10 @@
403
405
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
404
406
  chrome exists before the page scripts run. -->
405
407
  <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
406
- <script src="/builders/shell-game.js?v=2026-11-09-game-mode"></script>
408
+ <script src="/builders/shell-game.js?v=2026-11-10-options"></script>
407
409
  <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
408
- <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
409
- <script src="/builders/shell.js?v=2026-11-09-game-mode"></script>
410
+ <script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
411
+ <script src="/builders/shell.js?v=2026-11-10-character"></script>
410
412
  <script src="/builders/hall-dialog.js"></script>
411
413
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
412
414
  <script src="/builders/palette.js" defer></script>
@@ -414,10 +416,12 @@
414
416
  <script src="/builders/hall-kit.js"></script>
415
417
  <!-- shared record overlay (#/idea|blocker/N) — every hall page carries it; this
416
418
  page was the one gap (task 2172). -->
417
- <script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
419
+ <script src="/builders/task-detail.js?v=2026-11-10-options"></script>
418
420
  <!-- task 1005044: the old deep links to the agent settings that moved to My agents -->
419
421
  <script src="/builders/settings-moved.js?v=2026-11-03-moved"></script>
420
- <script src="/builders/settings.js?v=2026-11-03-moved"></script>
422
+ <!-- task 1005144: the ONE options menu — the rail, its search, and the screens it opens in a frame. -->
423
+ <script src="/builders/options-menu.js?v=2026-11-10-options"></script>
424
+ <script src="/builders/settings.js?v=2026-11-10-options"></script>
421
425
  <!-- task 1003341: the Active sessions panel. Its own file rather than more of
422
426
  settings.js, which sits close to the 1500-line size ratchet. -->
423
427
  <script src="/builders/settings-sessions.js?v=2026-08-29-sessions"></script>
@@ -426,7 +430,7 @@
426
430
  <script src="/builders/settings-ai-keys.js?v=2026-10-28-ai-keys"></script>
427
431
  <!-- task 1004296: Settings → Software update. Own file on the same precedent. -->
428
432
  <!-- the Update pill's flow, which the panel's Update button runs in place (task 1005041) -->
429
- <script src="/builders/update-pill.js?v=2026-11-03-pill"></script>
433
+ <script src="/builders/update-pill.js?v=2026-11-10-options"></script>
430
434
  <script src="/builders/settings-software-update.js?v=2026-11-03-pill"></script>
431
435
  <!-- task 1004501: Settings → Your Autobongos runner. Own file on the same precedent. -->
432
436
  <!-- task 1005094: what a device's Run button says (pure; loaded before the panel). -->