@bongos/core 1.24.85 → 1.24.87

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 (69) hide show
  1. package/.bongos-core.json +83 -73
  2. package/docs/adr/0402-helm-is-the-halls-look-and-the-hall-is-dark-only.md +15 -0
  3. package/docs/copy-inventory.md +22 -21
  4. package/docs/copy-registry.json +32 -23
  5. package/docs/module-api-changelog.md +4 -0
  6. package/docs/page-inventory.json +2 -0
  7. package/docs/page-readings.json +195 -195
  8. package/modules/hall-ui/public/ai-studio.html +1 -1
  9. package/modules/hall-ui/public/atlas.html +1 -1
  10. package/modules/hall-ui/public/blockers.html +1 -1
  11. package/modules/hall-ui/public/board-room.html +1 -1
  12. package/modules/hall-ui/public/city-draw.js +127 -69
  13. package/modules/hall-ui/public/city.css +37 -3
  14. package/modules/hall-ui/public/city.html +16 -5
  15. package/modules/hall-ui/public/city.js +26 -1
  16. package/modules/hall-ui/public/collab.html +1 -1
  17. package/modules/hall-ui/public/commands.html +1 -1
  18. package/modules/hall-ui/public/copy-desk.html +1 -1
  19. package/modules/hall-ui/public/craft-mode.js +4 -1
  20. package/modules/hall-ui/public/deploy.html +1 -1
  21. package/modules/hall-ui/public/goal-map.html +2 -2
  22. package/modules/hall-ui/public/goals.html +1 -1
  23. package/modules/hall-ui/public/government.html +1 -1
  24. package/modules/hall-ui/public/home-city-draw.js +88 -54
  25. package/modules/hall-ui/public/home-city.css +25 -3
  26. package/modules/hall-ui/public/idea.html +1 -1
  27. package/modules/hall-ui/public/ideas.html +1 -1
  28. package/modules/hall-ui/public/index.html +6 -4
  29. package/modules/hall-ui/public/market-watch-item.html +1 -1
  30. package/modules/hall-ui/public/market-watch-rules.html +1 -1
  31. package/modules/hall-ui/public/market-watch.html +1 -1
  32. package/modules/hall-ui/public/modules.html +1 -1
  33. package/modules/hall-ui/public/money.html +1 -1
  34. package/modules/hall-ui/public/my-agents.html +1 -1
  35. package/modules/hall-ui/public/options-menu.js +4 -0
  36. package/modules/hall-ui/public/primer.html +1 -1
  37. package/modules/hall-ui/public/profile.html +1 -1
  38. package/modules/hall-ui/public/project-settings.html +1 -1
  39. package/modules/hall-ui/public/roster.html +1 -1
  40. package/modules/hall-ui/public/settings.css +15 -0
  41. package/modules/hall-ui/public/settings.html +1 -1
  42. package/modules/hall-ui/public/shell-game.js +82 -2
  43. package/modules/hall-ui/public/sky-time.js +206 -0
  44. package/modules/hall-ui/public/street.html +2 -2
  45. package/modules/hall-ui/public/studio.html +1 -1
  46. package/modules/hall-ui/public/style.css +118 -1
  47. package/modules/hall-ui/public/task.html +1 -1
  48. package/modules/hall-ui/public/thinking.html +2 -2
  49. package/modules/hall-ui/public/tweak-editor.html +1 -1
  50. package/modules/hall-ui/public/visor.css +13 -14
  51. package/modules/hall-ui/public/watch.html +1 -1
  52. package/modules/hall-ui/public/work.html +1 -1
  53. package/modules/hall-ui/records/home-city.md +13 -0
  54. package/modules/hall-ui/records/living-city.md +12 -0
  55. package/modules/hall-ui/records/options-menu.md +7 -0
  56. package/modules/hall-ui/records/visor.md +1 -1
  57. package/modules/ui-design/public/brand.html +1 -1
  58. package/package-lock.json +2 -2
  59. package/package.json +1 -1
  60. package/release-notes.json +12 -0
  61. package/src/module-api.js +1 -1
  62. package/tests/hall_city.mjs +72 -22
  63. package/tests/hall_city_living.mjs +7 -2
  64. package/tests/hall_options_menu.mjs +63 -4
  65. package/tests/hall_sky_time.mjs +361 -0
  66. package/tests/hall_street.mjs +2 -1
  67. package/tests/hall_visor.mjs +18 -8
  68. package/tests/home_city.mjs +54 -5
  69. package/tests/page_notes_panel.mjs +9 -1
@@ -51,7 +51,7 @@
51
51
  <ul class="ref-list" role="list"><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--ok)" aria-hidden="true"></span><code class="ref-name">--ok</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#187444</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#4ade80</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--ok-weak)" aria-hidden="true"></span><code class="ref-name">--ok-weak</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, #187444 12%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, #4ade80 14%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--warn)" aria-hidden="true"></span><code class="ref-name">--warn</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#895c00</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#fbbf24</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--warn-weak)" aria-hidden="true"></span><code class="ref-name">--warn-weak</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, #895c00 14%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, #fbbf24 14%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--danger)" aria-hidden="true"></span><code class="ref-name">--danger</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#b42318</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#f87171</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--danger-weak)" aria-hidden="true"></span><code class="ref-name">--danger-weak</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, #b42318 10%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, #f87171 14%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--info)" aria-hidden="true"></span><code class="ref-name">--info</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--sea) 86%, #000000)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--sea) 80%, #ffffff)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--info-weak)" aria-hidden="true"></span><code class="ref-name">--info-weak</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--info) 9%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--info) 14%, var(--bg-card))</code></span></li></ul>
52
52
  <h3 class="ref-sub">Derived colours</h3>
53
53
  <p class="ref-note">Mixed from the thirteen, never typed as a new colour. Black and white with alpha appear only as a scrim, a shadow or glass.</p>
54
- <ul class="ref-list" role="list"><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass)" aria-hidden="true"></span><code class="ref-name">--glass</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .05)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .1)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass-strong)" aria-hidden="true"></span><code class="ref-name">--glass-strong</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .08)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .16)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass-edge)" aria-hidden="true"></span><code class="ref-name">--glass-edge</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .12)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .2)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void)" aria-hidden="true"></span><code class="ref-name">--void</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#050508</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#050d16</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void-ink)" aria-hidden="true"></span><code class="ref-name">--void-ink</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffffff</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--ink)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void-edge)" aria-hidden="true"></span><code class="ref-name">--void-edge</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .12)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .4)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--skeleton)" aria-hidden="true"></span><code class="ref-name">--skeleton</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--ink) 10%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--ink) 10%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-ink)" aria-hidden="true"></span><code class="ref-name">--accent-ink</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 45%, #240e00)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--accent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-lift)" aria-hidden="true"></span><code class="ref-name">--accent-lift</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 58%, #ffffff)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--accent) 58%, #ffffff)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-tint)" aria-hidden="true"></span><code class="ref-name">--accent-tint</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 30%, #fffdf9)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--accent) 22%, #050d16)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-on)" aria-hidden="true"></span><code class="ref-name">--accent-on</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2a1305</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2a1305</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--focus)" aria-hidden="true"></span><code class="ref-name">--focus</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent-deep) 82%, #3a1400)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--accent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--scrim)" aria-hidden="true"></span><code class="ref-name">--scrim</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(0, 0, 0, .55)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(0, 0, 0, .55)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--surface-2)" aria-hidden="true"></span><code class="ref-name">--surface-2</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--ink) 5%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--ink) 6%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--night-glass)" aria-hidden="true"></span><code class="ref-name">--night-glass</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--bg) 72%, transparent)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--bg) 72%, transparent)</code></span></li></ul>
54
+ <ul class="ref-list" role="list"><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass)" aria-hidden="true"></span><code class="ref-name">--glass</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .05)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .1)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass-strong)" aria-hidden="true"></span><code class="ref-name">--glass-strong</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .08)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .16)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--glass-edge)" aria-hidden="true"></span><code class="ref-name">--glass-edge</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .12)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .2)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void)" aria-hidden="true"></span><code class="ref-name">--void</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#050508</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#050d16</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void-ink)" aria-hidden="true"></span><code class="ref-name">--void-ink</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffffff</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--ink)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--void-edge)" aria-hidden="true"></span><code class="ref-name">--void-edge</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(23, 24, 26, .12)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(200, 241, 247, .4)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--skeleton)" aria-hidden="true"></span><code class="ref-name">--skeleton</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--ink) 10%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--ink) 10%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-ink)" aria-hidden="true"></span><code class="ref-name">--accent-ink</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 45%, #240e00)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--accent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-lift)" aria-hidden="true"></span><code class="ref-name">--accent-lift</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 58%, #ffffff)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--accent) 58%, #ffffff)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-tint)" aria-hidden="true"></span><code class="ref-name">--accent-tint</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent) 30%, #fffdf9)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--accent) 22%, #050d16)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--accent-on)" aria-hidden="true"></span><code class="ref-name">--accent-on</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2a1305</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2a1305</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--focus)" aria-hidden="true"></span><code class="ref-name">--focus</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--accent-deep) 82%, #3a1400)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>var(--accent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--scrim)" aria-hidden="true"></span><code class="ref-name">--scrim</code><span class="ref-val"><span class="ref-val__k">light</span> <code>rgba(0, 0, 0, .55)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>rgba(0, 0, 0, .55)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--surface-2)" aria-hidden="true"></span><code class="ref-name">--surface-2</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--ink) 5%, var(--bg-card))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--ink) 6%, var(--bg-card))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--night-glass)" aria-hidden="true"></span><code class="ref-name">--night-glass</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--bg) 72%, transparent)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--bg) 72%, transparent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--night-plate)" aria-hidden="true"></span><code class="ref-name">--night-plate</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--bg) 88%, transparent)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--bg) 88%, transparent)</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-top)" aria-hidden="true"></span><code class="ref-name">--sky-night-top</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#02060c</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#02060c</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-mid)" aria-hidden="true"></span><code class="ref-name">--sky-night-mid</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#07121f</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#07121f</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-cloud)" aria-hidden="true"></span><code class="ref-name">--sky-night-cloud</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#456780</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#456780</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-cloud-shade)" aria-hidden="true"></span><code class="ref-name">--sky-night-cloud-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#1a3348</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#1a3348</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-roof)" aria-hidden="true"></span><code class="ref-name">--sky-night-roof</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2a475e</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2a475e</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-lit)" aria-hidden="true"></span><code class="ref-name">--sky-night-lit</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#10263a</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#10263a</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-shade)" aria-hidden="true"></span><code class="ref-name">--sky-night-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#081522</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#081522</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-base)" aria-hidden="true"></span><code class="ref-name">--sky-night-base</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#3c5d75</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#3c5d75</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-lamp)" aria-hidden="true"></span><code class="ref-name">--sky-night-lamp</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffe9c9</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#ffe9c9</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-night-line)" aria-hidden="true"></span><code class="ref-name">--sky-night-line</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#8fb3c8</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#8fb3c8</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-top)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-top</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#050d16</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#050d16</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-mid)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-mid</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#17334a</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#17334a</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-cloud)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-cloud</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#fbe3c8</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#fbe3c8</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-cloud-shade)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-cloud-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#b08e8c</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#b08e8c</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-roof)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-roof</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#a9c0cc</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#a9c0cc</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-lit)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-lit</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#3f5b70</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#3f5b70</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-shade)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#1f3a50</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#1f3a50</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-base)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-base</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#f0c9ab</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#f0c9ab</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-lamp)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-lamp</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffe2c4</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#ffe2c4</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dawn-line)" aria-hidden="true"></span><code class="ref-name">--sky-dawn-line</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2f4b61</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2f4b61</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-top)" aria-hidden="true"></span><code class="ref-name">--sky-midday-top</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#1d5687</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#1d5687</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-mid)" aria-hidden="true"></span><code class="ref-name">--sky-midday-mid</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#4a90c2</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#4a90c2</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-cloud)" aria-hidden="true"></span><code class="ref-name">--sky-midday-cloud</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#fff6dc</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#fff6dc</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-cloud-shade)" aria-hidden="true"></span><code class="ref-name">--sky-midday-cloud-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#e8d2a8</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#e8d2a8</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-roof)" aria-hidden="true"></span><code class="ref-name">--sky-midday-roof</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#fff3d4</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#fff3d4</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-lit)" aria-hidden="true"></span><code class="ref-name">--sky-midday-lit</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#dcc79c</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#dcc79c</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-shade)" aria-hidden="true"></span><code class="ref-name">--sky-midday-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#7f93a8</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#7f93a8</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-base)" aria-hidden="true"></span><code class="ref-name">--sky-midday-base</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffe6b3</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#ffe6b3</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-lamp)" aria-hidden="true"></span><code class="ref-name">--sky-midday-lamp</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#fff6dc</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#fff6dc</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-midday-line)" aria-hidden="true"></span><code class="ref-name">--sky-midday-line</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2f679a</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2f679a</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-top)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-top</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#0a0f24</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#0a0f24</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-mid)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-mid</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#2a2552</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#2a2552</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-cloud)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-cloud</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffc79a</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#ffc79a</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-cloud-shade)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-cloud-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#a8748a</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#a8748a</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-roof)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-roof</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#c7a3b0</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#c7a3b0</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-lit)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-lit</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#4a4470</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#4a4470</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-shade)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-shade</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#231f44</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#231f44</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-base)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-base</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#f6b596</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#f6b596</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-lamp)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-lamp</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#ffe2c4</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#ffe2c4</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-dusk-line)" aria-hidden="true"></span><code class="ref-name">--sky-dusk-line</code><span class="ref-val"><span class="ref-val__k">light</span> <code>#302b55</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>#302b55</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-now-haze)" aria-hidden="true"></span><code class="ref-name">--sky-now-haze</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--sky-now-mid) 55%, var(--sky-now-cloud))</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--sky-now-mid) 55%, var(--sky-now-cloud))</code></span></li><li class="ref-row ref-row--colour"><span class="ref-swatch" style="background: var(--sky-now-glow)" aria-hidden="true"></span><code class="ref-name">--sky-now-glow</code><span class="ref-val"><span class="ref-val__k">light</span> <code>color-mix(in srgb, var(--sky-now-lamp) calc(var(--sky-now-windows) * 100%), transparent)</code></span><span class="ref-val"><span class="ref-val__k">dark</span> <code>color-mix(in srgb, var(--sky-now-lamp) calc(var(--sky-now-windows) * 100%), transparent)</code></span></li></ul>
55
55
  </section>
56
56
  <section class="scroll ref-sec" id="ref-type" aria-labelledby="ref-type-h">
57
57
  <h2 class="scroll__h" id="ref-type-h">Type</h2>
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.85",
3
+ "version": "1.24.87",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.85",
9
+ "version": "1.24.87",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.85",
3
+ "version": "1.24.87",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -11613,5 +11613,17 @@
11613
11613
  "id": "1005096",
11614
11614
  "text": "Autobongos now runs on a Mac for real: the setup command, start, stop and remove all proven on one, and the Mac-only test failures are gone."
11615
11615
  }
11616
+ ],
11617
+ "1.24.86": [
11618
+ {
11619
+ "id": "1005208",
11620
+ "text": "In game mode, Options now opens as a smaller see-through window over where you are, with smaller text, and the artist palette no longer shows twice."
11621
+ }
11622
+ ],
11623
+ "1.24.87": [
11624
+ {
11625
+ "id": "1005196",
11626
+ "text": "The city now stands in the clouds: the same buildings with no ground, wrapped in cloud and lit from below. It changes with the time of day, from a deep night with lit windows through a warm dawn to a bright midday and dusk."
11627
+ }
11616
11628
  ]
11617
11629
  }
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.24.85'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.87'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -3,9 +3,11 @@
3
3
  // WHAT IT GUARDS. The page is the home view of the reference design
4
4
  // (docs/design/mocks/governor-city/Street.dc.html) built over the governor
5
5
  // docket (task 1004523) and the open goals' task rollups. What can go wrong:
6
- // * the drawing drifts from the prototype (a civic recipe, the ground, a pin
7
- // position) — pinned by running the PROTOTYPE'S OWN Component class beside
8
- // city-draw.js and comparing the paths they emit, in both modes;
6
+ // * the drawing's GEOMETRY drifts from the prototype (a civic recipe, the lanes,
7
+ // the plaza, a pin position) — pinned by running the PROTOTYPE'S OWN Component
8
+ // class beside city-draw.js and comparing the paths they emit. The COLOURS are
9
+ // no longer the prototype's: since task 1005196 the city stands in cloud and is
10
+ // painted from the hour's sky tokens, which the palette test below pins;
9
11
  // * a pin drawn in the wrong state or over the wrong building, or invented
10
12
  // where the docket has no matter;
11
13
  // * a district for a goal that is not open, two goals on one plot, a plot on
@@ -25,7 +27,6 @@ import path from 'node:path';
25
27
  import vm from 'node:vm';
26
28
  import { createRequire } from 'node:module';
27
29
  import { fileURLToPath } from 'node:url';
28
- import { cityTokens } from './helpers.mjs';
29
30
 
30
31
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
31
32
  const PUB = path.join(ROOT, 'modules/hall-ui/public');
@@ -57,23 +58,69 @@ const rollup = (id, c) => ({ goal_id: String(id), done: 0, active: 0, ready: 0,
57
58
 
58
59
  // ── the drawing is the prototype's ───────────────────────────────────────────
59
60
 
60
- test('the nine civic recipes draw exactly the prototype paths, in both modes', () => {
61
- for (const mode of ['dark', 'light']) {
62
- const p = new Proto({ mode });
63
- const T = p.theme(mode);
64
- const pk = p.isoKit(60, 30, 720, 176, 30 / 28, T.iso, false);
65
- const ck = City.isoKit(60, 30, 720, 176, 30 / 28, City.isoTheme(mode), false);
66
- for (const [kind, x, y] of City.CIVIC_SLOTS) {
67
- const a = []; const b = [];
68
- p.isoInstitution(a, pk, kind, x, y, { fixes: false });
69
- City.isoInstitution(b, ck, kind, x, y, { fixes: false });
70
- assert.deepEqual(b, cityTokens(a), `${mode} ${kind}`);
71
- }
61
+ // The shape of a path list, without its paint: what the prototype fixes since task 1005196.
62
+ const shape = (list) => list.map((p) => ({ d: p.d, dash: p.dash, w: p.w }));
63
+
64
+ test('the nine civic recipes draw exactly the prototype paths (the geometry; the paint is the sky\'s)', () => {
65
+ const p = new Proto({ mode: 'dark' });
66
+ const pk = p.isoKit(60, 30, 720, 176, 30 / 28, p.theme('dark').iso, false);
67
+ const ck = City.isoKit(60, 30, 720, 176, 30 / 28, City.isoTheme(), false);
68
+ for (const [kind, x, y] of City.CIVIC_SLOTS) {
69
+ const a = []; const b = [];
70
+ p.isoInstitution(a, pk, kind, x, y, { fixes: false });
71
+ City.isoInstitution(b, ck, kind, x, y, { fixes: false });
72
+ assert.deepEqual(shape(b), shape(a), kind);
73
+ }
74
+ });
75
+
76
+ // Task 1005196: the city in the clouds. Every face and line is one of the hour's sky
77
+ // tokens (or the hall's own), never a typed-in colour, and the mode changes nothing.
78
+ test('the iso sub-palette is the hour\'s sky tokens: no literal, one palette whatever the mode', () => {
79
+ const I = City.isoTheme();
80
+ assert.deepEqual(City.isoTheme('light'), I, 'the hall is dark only: a mode argument is ignored');
81
+ const values = [];
82
+ (function walk(v) { if (typeof v === 'string') values.push(v); else if (v && typeof v === 'object') Object.values(v).forEach(walk); })(I);
83
+ assert.ok(values.length > 40);
84
+ for (const v of values) {
85
+ if (/^\d+ \d+$/.test(v)) continue; // a dash pattern
86
+ assert.doesNotMatch(v, /#[0-9a-f]{3,8}\b|rgba?\(|hsla?\(/i, `${v}: no colour literal`);
87
+ assert.match(v, /var\(--sky-now-[a-z-]+\)/, `${v}: spends a sky token`);
88
+ }
89
+ for (const key of ['ground', 'groundLine', 'road']) assert.equal(I[key], undefined, `no ${key}: the city has no ground`);
90
+ // a face on the ground fades into the cloud: the side's gradient, then its plain colour as the fallback
91
+ assert.equal(I.civic.lg, 'url(#sky-face-l) var(--sky-now-lit)');
92
+ assert.equal(I.civic.rg, 'url(#sky-face-r) var(--sky-now-shade)');
93
+ const k = City.isoKit(60, 30, 720, 176, 30 / 28, I, false);
94
+ const onGround = []; const raised = [];
95
+ City.isoBox(onGround, k, 0, 0, 1, 1, 0, 40, I.civic);
96
+ City.isoBox(raised, k, 0, 0, 1, 1, 12, 40, I.civic);
97
+ assert.deepEqual(onGround.map((p) => p.f), [I.civic.lg, I.civic.rg, I.civic.t], 'a box on the ground stands in the cloud');
98
+ assert.deepEqual(raised.map((p) => p.f), [I.civic.l, I.civic.r, I.civic.t], 'a box above it keeps its plain faces');
99
+ // the gradients the page defines: a pair for the clear city, a pair per haze share in use
100
+ const defs = City.skyDefs([0.62, 0.62, 0.3]);
101
+ assert.deepEqual(defs.map((d) => d.id), ['sky-face-l', 'sky-face-r', 'sky-face-l-h62', 'sky-face-r-h62', 'sky-face-l-h30', 'sky-face-r-h30']);
102
+ for (const d of defs) {
103
+ assert.deepEqual(d.stops.map((s) => s[0]), [0, 0.5, 1]);
104
+ assert.match(d.stops[2][1], /--sky-now-base/, `${d.id} ends in the cloud's colour`);
72
105
  }
73
106
  });
74
107
 
75
- test('the iso sub-palette is the prototype theme().iso, both modes', () => {
76
- for (const mode of ['dark', 'light']) assert.deepEqual(City.isoTheme(mode), cityTokens(new Proto({ mode }).theme(mode).iso), mode);
108
+ test('the city stands in cloud: banks behind and in front, a puff at each building\'s foot, stars for the night', () => {
109
+ const m = City.cityModel({ docket: docket([matter()]), goals: [goal(1)], rollups: [rollup(1, { done: 6, active: 1 })] });
110
+ assert.deepEqual(m.clouds.back.map((c) => c.cls), ['city-cloud city-cloud--far', 'city-cloud city-cloud--back']);
111
+ assert.deepEqual(m.clouds.front.map((c) => c.cls), ['city-cloud city-cloud--near', 'city-cloud city-cloud--shade', 'city-cloud city-cloud--dark']);
112
+ assert.ok(m.clouds.rows.length >= 5, 'the nine civic buildings stand in five depth rows');
113
+ const depths = m.clouds.rows.map((r) => r.depth);
114
+ assert.deepEqual(depths, depths.slice().sort((a, b) => a - b), 'rows come back to front');
115
+ for (const c of [...m.clouds.back, ...m.clouds.rows, ...m.clouds.front, m.stars]) {
116
+ assert.equal(c.f, 'none'); assert.equal(c.s, 'none');
117
+ assert.match(c.cls, /^city-(cloud|stars)/, 'the sheet gives it its sky token: no fill is typed in');
118
+ assert.match(c.d, /^M[-\d.]+ [-\d.]+a/);
119
+ }
120
+ assert.ok([...m.clouds.back, ...m.clouds.rows, ...m.clouds.front].every((c) => City.SOFT.includes(c.soft)), 'every bank names one of the two filters');
121
+ assert.deepEqual(m.defs.map((d) => d.id).slice(0, 2), ['sky-face-l', 'sky-face-r']);
122
+ // the model is the same at every hour: the hour repaints through the tokens, never a redraw
123
+ assert.equal(JSON.stringify(m).match(/#[0-9a-f]{6}\b/i), null, 'no colour literal anywhere in the model');
77
124
  });
78
125
 
79
126
  test('every work kind the prototype draws is drawn the same way', () => {
@@ -84,11 +131,11 @@ test('every work kind the prototype draws is drawn the same way', () => {
84
131
  const a = []; const b = [];
85
132
  p.isoWork(a, pk, 6, 2, kind, 58);
86
133
  City.isoWork(b, ck, 6, 2, kind, 58);
87
- assert.deepEqual(b, cityTokens(a), kind);
134
+ assert.deepEqual(shape(b), shape(a), kind);
88
135
  }
89
136
  });
90
137
 
91
- test('the ground, ring road, lanes and plaza are the prototype home view, path for path', () => {
138
+ test('the ring road\'s lanes and the plaza are the prototype home view, path for path; the ground and the road fill are gone', () => {
92
139
  const p = new Proto({ mode: 'light' });
93
140
  p.state = p.initial();
94
141
  p.state.reviewHeld = true;
@@ -96,7 +143,10 @@ test('the ground, ring road, lanes and plaza are the prototype home view, path f
96
143
  const home = p.homeView(T, p.matters(), false);
97
144
  const model = City.cityModel({ docket: docket([matter()]), goals: [], rollups: [], mode: 'light' });
98
145
  // The prototype's flat list is ground, 4 roads, lanes, plaza, then its 4 plots and their grid.
99
- assert.deepEqual(model.flat.slice(0, 7), cityTokens(home.flat.slice(0, 7)));
146
+ // The city in the clouds keeps the lanes and the plaza and draws no ground and no road fill.
147
+ assert.deepEqual(shape(model.flat.slice(0, 2)), shape(home.flat.slice(5, 7)));
148
+ const gone = new Set(home.flat.slice(0, 5).map((p) => p.d));
149
+ assert.ok(!model.flat.some((p) => gone.has(p.d)), 'no ground plane, no road fill');
100
150
  });
101
151
 
102
152
  test('with four goals the districts sit on the prototype\'s four plots, in its order', () => {
@@ -290,7 +340,7 @@ test('the city sits in the hall chrome, behind the shell\'s full-screen switch',
290
340
  // task 1004685 (the living city): gov-living.js, the model under the drawing, and
291
341
  // gov-feeds.js, its one reader per page (shared with the shell's tally), load before it
292
342
  // task 1004702: the card answers its first ask in place, so the deck's card and sender (and the desk rows under them) load before the page
293
- assert.deepEqual(scripts, ['dom-utils', 'shell-game', 'shell-trail', 'craft-mode', 'shell', 'hall-dialog', 'visor', 'palette', 'gov-living', 'gov-feeds', 'city-draw', 'hall-kit', 'street-draw', 'street-card', 'street-inside', 'street-desk', 'street-deck', 'city-decide', 'city-switchboard', 'city'], 'the shell first, then the shared dialog (task 1005085) and the visor (task 1005148)');
343
+ assert.deepEqual(scripts, ['dom-utils', 'shell-game', 'shell-trail', 'craft-mode', 'shell', 'hall-dialog', 'visor', 'palette', 'gov-living', 'gov-feeds', 'sky-time', 'city-draw', 'hall-kit', 'street-draw', 'street-card', 'street-inside', 'street-desk', 'street-deck', 'city-decide', 'city-switchboard', 'city'], 'the shell first, then the shared dialog (task 1005085) and the visor (task 1005148)');
294
344
  // task 1004925: every script but dom-utils.js is deferred, so none holds up the
295
345
  // parser; defer runs them in document order, which is why the order above still
296
346
  // holds. dom-utils.js stays synchronous: the one-escaper guard
@@ -250,8 +250,13 @@ test('quiet buildings sit darker; busy ones keep the prototype\'s recipe exactly
250
250
  else assert.deepEqual(recipe, ref.map((p) => p.f), `${s[0]} is busy: the recipe is untouched`);
251
251
  }
252
252
  assert.deepEqual(m.civic.filter((c) => c.quiet).map((c) => c.key).sort(), ['automation', 'people', 'rules'], 'no agent and no ask: Automation (its switch is a standing state, not an ask), Rules and People');
253
- assert.equal(City.mixToward('#808080', '#000000', 0.5), '#404040');
254
- assert.equal(City.mixToward('rgba(255,255,255,0.4)', '#000000', 0.5), 'rgba(255,255,255,0.2)', 'a line thins out');
253
+ // the haze is a mix of tokens (task 1005196): a solid face goes toward the haze, a line thins out, a fading face takes its hazed gradient
254
+ const I = City.isoTheme(), H = City.hazeTheme(I, 0.5);
255
+ assert.equal(H.civic.t, 'color-mix(in srgb, var(--sky-now-roof) 50%, var(--sky-now-haze))');
256
+ assert.equal(H.civic.s, 'color-mix(in srgb, ' + I.civic.s + ' 50%, transparent)', 'a line thins out');
257
+ assert.match(H.civic.lg, /^url\(#sky-face-l-h50\) /);
258
+ assert.equal(City.hazeTheme(I, 0), I, 'no haze is the palette itself');
259
+ assert.equal(City.mixToward, undefined, 'the literal colour maths left with the literals');
255
260
  });
256
261
 
257
262
  // ── ground: haze and the spend conduit ─────────────────────────────────────
@@ -138,7 +138,7 @@ test('the Settings page IS the menu: one search over the groups, loaded before s
138
138
 
139
139
  // ---- shell-game.js: the embedded page and game mode's Escape --------------------
140
140
 
141
- function bootGame({ search = '', framed = true, game = false, path: p = '/my-agents' } = {}) {
141
+ function bootGame({ search = '', framed = true, game = false, path: p = '/my-agents', dom = false } = {}) {
142
142
  const docListeners = {};
143
143
  const winListeners = {};
144
144
  const timers = [];
@@ -156,13 +156,40 @@ function bootGame({ search = '', framed = true, game = false, path: p = '/my-age
156
156
  win.parent = framed ? parent : win;
157
157
  const document = {
158
158
  documentElement: root,
159
- body: { setAttribute(k, v) { bodyAttrs[k] = v; } },
159
+ body: { setAttribute(k, v) { bodyAttrs[k] = v; }, getAttribute: (k) => (k in bodyAttrs ? bodyAttrs[k] : null) },
160
160
  addEventListener(t, fn) { (docListeners[t] ||= []).push(fn); },
161
161
  };
162
+ // dom: enough of a page for the game's options window to be drawn (createElement,
163
+ // a sibling the window makes inert, a frame that keeps its src), with OTBDialog.bind
164
+ // standing in for hall-dialog.js (its trap, Escape and focus return are tested there).
165
+ const windows = [];
166
+ const bound = [];
167
+ const sibling = { attrs: {}, setAttribute(k, v) { this.attrs[k] = v; }, hasAttribute(k) { return k in this.attrs; }, removeAttribute(k) { delete this.attrs[k]; } };
168
+ if (dom) {
169
+ document.body.children = [sibling];
170
+ document.body.appendChild = (el) => { windows.push(el); document.body.children.push(el); return el; };
171
+ document.createElement = () => {
172
+ const frameAttrs = {};
173
+ const frame = { getAttribute: (k) => (k in frameAttrs ? frameAttrs[k] : null), setAttribute: (k, v) => { frameAttrs[k] = v; }, focus() {} };
174
+ const box = { box: true };
175
+ return { hidden: false, innerHTML: '', querySelector: (sel) => (sel === '.opt-window__box' ? box : frame), frame, box };
176
+ };
177
+ win.OTBDialog = {
178
+ bind(root, opts) {
179
+ let open = false;
180
+ bound.push({ root, opts });
181
+ return {
182
+ open() { if (open) return; open = true; root.hidden = false; root.classes = [opts.lockClass]; opts.onOpen(); },
183
+ close() { if (!open) return; open = false; root.hidden = true; root.classes = []; opts.onClose(); },
184
+ isOpen: () => open,
185
+ };
186
+ },
187
+ };
188
+ }
162
189
  const ctx = vm.createContext({ window: win, document, URLSearchParams, URL });
163
190
  vm.runInContext(read('shell-game.js'), ctx);
164
191
  return {
165
- root, bodyAttrs, parent, assigned, game: win.OTBShellGame,
192
+ root, bodyAttrs, parent, assigned, windows, bound, sibling, win, game: win.OTBShellGame,
166
193
  press(key, target = { tagName: 'DIV' }) {
167
194
  const ev = { key, target, defaultPrevented: false, preventDefault() { this.defaultPrevented = true; } };
168
195
  for (const fn of winListeners.keydown || []) fn(ev);
@@ -173,7 +200,7 @@ function bootGame({ search = '', framed = true, game = false, path: p = '/my-age
173
200
  const attrs = { href };
174
201
  if (target) attrs.target = target;
175
202
  const a = { getAttribute: (k) => (k in attrs ? attrs[k] : null), setAttribute: (k, v) => { attrs[k] = v; } };
176
- for (const fn of docListeners.click || []) fn({ target: { closest: () => a } });
203
+ for (const fn of docListeners.click || []) fn({ target: { closest: () => a }, preventDefault() { this.defaultPrevented = true; } });
177
204
  return attrs.target || null;
178
205
  },
179
206
  };
@@ -214,6 +241,38 @@ test('GAME MODE: on the menu itself the last Escape closes it; outside game mode
214
241
  assert.deepEqual(off.assigned, [], 'outside game mode the press stays the shell\'s');
215
242
  });
216
243
 
244
+ test('GAME MODE: away from the menu, Escape opens the options as a window over the place, and Escape again shuts it', () => {
245
+ const city = bootGame({ game: true, framed: false, path: '/city', dom: true });
246
+ city.press('Escape');
247
+ assert.deepEqual(city.assigned, [], 'the place stays: no page change');
248
+ assert.equal(city.windows.length, 1, 'one window drawn over it');
249
+ assert.equal(city.windows[0].frame.getAttribute('src'), '/settings?embed=1', 'the menu, framed and chromeless');
250
+ assert.equal(city.bound.length, 1, 'the window is the shared dialog: OTBDialog.bind owns Escape, the scrim, the focus trap and return');
251
+ assert.equal(city.bound[0].opts.panel, city.windows[0].box, 'the glass box is the dialog panel');
252
+ assert.equal(city.bound[0].opts.lockClass, 'opt-window-open', 'the page behind stops scrolling');
253
+ assert.equal(city.bound[0].opts.initialFocus(), city.windows[0].frame, 'focus goes into the menu');
254
+ assert.equal(city.sibling.hasAttribute('inert'), true, 'the page behind is inert, so Tab out of the frame cannot reach it');
255
+ assert.equal(city.win.OTBOptionsOverlay.isOpen(), true);
256
+ city.press('Escape');
257
+ assert.equal(city.win.OTBOptionsOverlay.isOpen(), false, 'the second Escape shuts it');
258
+ assert.equal(city.sibling.hasAttribute('inert'), false, 'and the page behind is live again');
259
+ city.press('Escape');
260
+ assert.equal(city.windows.length, 1, 'reopening reuses the one window');
261
+ assert.equal(city.bound.length, 1, 'bound once');
262
+ // a link to the menu (the visor's Options row) opens the window at that screen
263
+ city.win.OTBOptionsOverlay.close();
264
+ city.click('/settings?from=%2Fcity#access');
265
+ assert.equal(city.windows[0].frame.getAttribute('src'), '/settings?embed=1#access', 'the screen it named, without ?from=');
266
+ assert.equal(city.win.OTBOptionsOverlay.isOpen(), true);
267
+ // outside game mode the link is a link
268
+ const off = bootGame({ game: false, framed: false, path: '/city', dom: true });
269
+ off.click('/settings');
270
+ assert.equal(off.windows.length, 0);
271
+ // and the menu, closing inside the window, shuts the window rather than leaving the page
272
+ const om = read('options-menu.js');
273
+ assert.ok(om.includes('window.parent.OTBOptionsOverlay') && om.includes('holder.close(); return;'), 'close() shuts the window first');
274
+ });
275
+
217
276
  test('options-menu.js gives the menu its Escape: close in game mode, nothing outside it', () => {
218
277
  const src = read('options-menu.js');
219
278
  assert.match(src, /function escape\(\) \{\s*var game = window\.OTBShellGame;\s*if \(game && game\.on && game\.on\(\)\) close\(\);/);