@bongos/core 1.21.29 → 1.21.31

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 (60) hide show
  1. package/.bongos-core.json +70 -65
  2. package/docs/copy-inventory.md +374 -389
  3. package/docs/copy-registry.json +472 -637
  4. package/docs/module-api-changelog.md +4 -0
  5. package/docs/page-readings.json +873 -883
  6. package/modules/hall-ui/public/atlas.html +3 -3
  7. package/modules/hall-ui/public/blockers.html +3 -3
  8. package/modules/hall-ui/public/board-room.html +3 -3
  9. package/modules/hall-ui/public/city.html +3 -3
  10. package/modules/hall-ui/public/collab.html +3 -3
  11. package/modules/hall-ui/public/commands.html +3 -3
  12. package/modules/hall-ui/public/copy-desk.html +3 -3
  13. package/modules/hall-ui/public/craft-mode.js +57 -3
  14. package/modules/hall-ui/public/deploy.html +3 -3
  15. package/modules/hall-ui/public/diagrams.html +3 -3
  16. package/modules/hall-ui/public/drachmae.html +3 -3
  17. package/modules/hall-ui/public/fleet.html +3 -3
  18. package/modules/hall-ui/public/gate.html +3 -3
  19. package/modules/hall-ui/public/goal-map.html +3 -3
  20. package/modules/hall-ui/public/goals.html +3 -3
  21. package/modules/hall-ui/public/government.html +3 -3
  22. package/modules/hall-ui/public/idea.html +3 -3
  23. package/modules/hall-ui/public/ideas.html +3 -3
  24. package/modules/hall-ui/public/index.html +3 -3
  25. package/modules/hall-ui/public/modules.html +3 -3
  26. package/modules/hall-ui/public/primer.html +3 -3
  27. package/modules/hall-ui/public/profile.html +3 -3
  28. package/modules/hall-ui/public/project-settings.html +3 -3
  29. package/modules/hall-ui/public/ranks.html +3 -3
  30. package/modules/hall-ui/public/roadmap.html +3 -3
  31. package/modules/hall-ui/public/roster.html +3 -3
  32. package/modules/hall-ui/public/sessions.html +3 -3
  33. package/modules/hall-ui/public/settings.html +3 -3
  34. package/modules/hall-ui/public/shell.js +2 -0
  35. package/modules/hall-ui/public/street.html +3 -3
  36. package/modules/hall-ui/public/studio.html +3 -3
  37. package/modules/hall-ui/public/style.css +2 -0
  38. package/modules/hall-ui/public/task.html +3 -3
  39. package/modules/hall-ui/public/thinking.html +3 -3
  40. package/modules/hall-ui/public/tweak-editor.html +3 -3
  41. package/modules/hall-ui/public/watch.html +3 -3
  42. package/modules/hall-ui/public/work.html +3 -3
  43. package/modules/hall-ui/records/craft-mode.md +7 -0
  44. package/modules/public-landing/public/projects-hall-live.states.json +1 -41
  45. package/modules/public-landing/public/projects.html +109 -72
  46. package/modules/public-landing/public/projects.probes.json +5 -5
  47. package/modules/public-landing/public/projects.states.json +7 -7
  48. package/package-lock.json +2 -2
  49. package/package.json +1 -1
  50. package/release-notes.json +12 -0
  51. package/src/module-api.js +1 -1
  52. package/tests/craft_mode_nav.mjs +202 -0
  53. package/tests/hall_tweak_editor.mjs +1 -1
  54. package/tests/nav_permission_atoms.mjs +1 -1
  55. package/tests/projects_hub.mjs +7 -4
  56. package/tests/projects_hub_app_step.mjs +4 -3
  57. package/tests/projects_hub_module_picker.mjs +12 -10
  58. package/tests/projects_hub_pre_uat.mjs +1 -1
  59. package/tests/wizard_physics_more.mjs +58 -34
  60. package/tests/wizard_six_screens.mjs +10 -8
@@ -171,9 +171,9 @@
171
171
 
172
172
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
- <script src="/builders/shell-trail.js?v=2026-10-02-craft"></script>
175
- <script src="/builders/craft-mode.js?v=2026-10-02-craft"></script>
176
- <script src="/builders/shell.js?v=2026-10-02-craft"></script>
174
+ <script src="/builders/shell-trail.js?v=2026-10-03-nav"></script>
175
+ <script src="/builders/craft-mode.js?v=2026-10-03-nav"></script>
176
+ <script src="/builders/shell.js?v=2026-10-03-nav"></script>
177
177
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
178
178
  <script src="/builders/palette.js" defer></script>
179
179
  <!-- shared frontend toolkit (window.OTB) — loaded FIRST so work.js can pull from it. -->
@@ -20,3 +20,10 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
20
20
  ## The carve
21
21
 
22
22
  `shell.js` sat at exactly 1,500 lines, the fitness ratchet, so the Back link + trail section (tasks 1004430/1004476/1004477) moved verbatim into `shell-trail.js` (`window.OTBShellTrail.make({ esc, nav })`). Behaviour is unchanged; `tests/hall_fullscreen.mjs` loads it before the shell and still drives the trail through the real top bar.
23
+
24
+ ## The nav follows the mode (task 1004493)
25
+
26
+ - **Each craft has a named tab list**, `MODE_TABS` in `craft-mode.js`, by NAV id. `ALWAYS_TABS` is the owner's list of tabs no mode may hide (2026-10-01: Builders, NAV id `roster`, first), and every mode's list is `ALWAYS_TABS` plus its own. Legacy and no mode have no entry, so they show every tab, as before.
27
+ - **Government shows only in Governing**, and outside that group Governing is the shortest list (Blockers, Board Room). Building is every tab except Government and the Board Room; Artistry is Studio, Goals, Your thinking; Ideating is Sky, Your thinking, Goals. The prototype names rooms that do not exist yet (Store, Page reviews, Treasury); a list names only real NAV items, and `tests/craft_mode_nav.mjs` requires every NAV item to sit in some mode.
28
+ - **The mode only ever takes away, and never through `hidden`.** The access gate owns `hidden`; `applyNav()` marks what the mode leaves out with `[data-craft-off]`, which `style.css` hides. So a mode can never show a tab the gate hid, and switching mode just moves the attribute. A group head goes too once nothing under it shows.
29
+ - **Two callers.** `apply()` runs it on every mode change (live, no reload), and `shell.js` `applyAccess` runs it right after its gate loop, so a later `/me` answer (a promotion, a permission) brings a head back with its tabs. Hidden tabs still open by their URL; nothing is enforced (ADR 0016).
@@ -99,14 +99,6 @@
99
99
  "wait",
100
100
  700
101
101
  ],
102
- [
103
- "click",
104
- "#reviewRows .setRow[data-row=\"code\"] [data-row-ok]"
105
- ],
106
- [
107
- "wait",
108
- 200
109
- ],
110
102
  [
111
103
  "click",
112
104
  "#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"
@@ -135,39 +127,7 @@
135
127
  ],
136
128
  [
137
129
  "click",
138
- "#reviewRows .setRow[data-row=\"address\"] [data-row-use]"
139
- ],
140
- [
141
- "wait",
142
- 200
143
- ],
144
- [
145
- "click",
146
- "#reviewRows .setRow[data-row=\"app\"] [data-row-ok]"
147
- ],
148
- [
149
- "wait",
150
- 150
151
- ],
152
- [
153
- "click",
154
- "#reviewRows .setRow[data-row=\"extras\"] [data-row-ok]"
155
- ],
156
- [
157
- "wait",
158
- 150
159
- ],
160
- [
161
- "click",
162
- "#reviewRows .setRow[data-row=\"team\"] [data-row-ok]"
163
- ],
164
- [
165
- "wait",
166
- 150
167
- ],
168
- [
169
- "click",
170
- "#reviewRows .setRow[data-row=\"run\"] [data-row-ok]"
130
+ "#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"
171
131
  ],
172
132
  [
173
133
  "wait",
@@ -269,12 +269,13 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
269
269
  .fillOffer{margin:0 0 12px;}
270
270
  .wizRecap{margin:22px 0 0;font-size:15px;line-height:1.5;color:var(--ink-soft);}
271
271
  #view-new .doorPill .btn[disabled]{opacity:.35;cursor:default;}
272
- /* the review: one hairline ledger of rows. Each row is its label, its value with one
273
- plain line under it, and two actions — Looks right (the accent, softly) and Change.
274
- A confirmed row settles to a quiet tick; an open row shows the old step's own controls
275
- under its value, and Continue below stays locked until every row is confirmed. */
272
+ /* the review: one hairline ledger of rows (task 1004550). Each row is its label, its
273
+ value with one plain line under it, and one action — Edit, which reads Done while the
274
+ row is open over the old step's own controls. One "Looks right, continue" under the
275
+ ledger confirms them all. Inside an open row the choices are compact toggles, not the
276
+ full-width hairline cards the question screens use. */
276
277
  .setRows{margin:24px 0 0;border-top:1px solid var(--rule);}
277
- .setRow{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:0 16px;align-items:start;padding:16px 0;border-bottom:1px solid var(--rule);}
278
+ .setRow{display:grid;grid-template-columns:120px minmax(0,1fr) auto;gap:0 16px;align-items:start;padding:14px 0;border-bottom:1px solid var(--rule);}
278
279
  .setRow[hidden]{display:none;}
279
280
  .setRow .k{font-size:13px;line-height:22px;color:var(--ink-faint);padding-top:2px;}
280
281
  .setRow .v{min-width:0;}
@@ -283,16 +284,31 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
283
284
  .setRow .rowS:empty{display:none;}
284
285
  .setRow .acts{display:flex;gap:6px;flex:none;}
285
286
  .setRow .acts button{min-height:34px;padding:0 14px;border-radius:999px;font:inherit;font-size:13px;white-space:nowrap;cursor:pointer;}
286
- .setRow [data-row-ok]{border:1px solid color-mix(in srgb,var(--accent) 55%,transparent);background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--ink);}
287
287
  .setRow [data-row-chg]{border:1px solid var(--glass-edge);background:var(--glass);color:var(--ink-soft);}
288
288
  .setRow [data-row-chg]:hover{color:var(--ink);}
289
289
  .setRow [data-row-chg][hidden]{display:none;}
290
- .setRow.done .rowV{color:var(--ink-soft);}
291
- .setRow.done [data-row-ok]{border-color:transparent;background:none;color:var(--accent);cursor:default;}
292
- .setRow.done [data-row-ok]::before{content:"✓ ";}
293
- .setRow.open [data-row-ok]{display:none;}
294
- .setRow .opts{margin-top:14px;}
295
- .setRow .opts .rowUse{margin-top:6px;}
290
+ .setRow.open [data-row-chg]{border-color:color-mix(in srgb,var(--accent) 55%,transparent);background:color-mix(in srgb,var(--accent) 14%,transparent);color:var(--ink);}
291
+ .setRow .opts{margin-top:12px;}
292
+ .setRow .opts .wizField{margin-bottom:12px;}
293
+ .setRow .opts .hint:empty{display:none;}
294
+ /* compact toggles: the repo choice and every short pill group in an open row */
295
+ .setRow .opts .choices,
296
+ .setRow .opts .typeCards.physCells:not(.physSuiteGrid),
297
+ .setRow .opts #teamCards{display:inline-flex;flex-wrap:wrap;gap:0;border:1px solid var(--rule);border-radius:999px;padding:3px;margin:0 8px 12px 0;vertical-align:top;}
298
+ .setRow .opts .choices .choice,
299
+ .setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill,
300
+ .setRow .opts #teamCards .tpill{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:0 14px;border:0;border-radius:999px;font-size:14px;font-weight:500;color:var(--ink-soft);background:none;}
301
+ .setRow .opts .choices .choice b{margin:0;font-size:14px;color:inherit;}
302
+ .setRow .opts .choices .choice b::before,
303
+ .setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill::before,
304
+ .setRow .opts #teamCards .tpill::before{display:none;}
305
+ .setRow .opts .choices .choice p{display:none;}
306
+ .setRow .opts .reassure{font-size:13px;margin:0 0 12px;}
307
+ .setRow .opts .choices .choice[aria-pressed=true],
308
+ .setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill[aria-pressed=true],
309
+ .setRow .opts #teamCards .tpill[aria-pressed=true]{background:color-mix(in srgb,var(--accent) 18%,transparent);color:var(--ink);}
310
+ /* a reason for a question the table hides explains nothing on screen */
311
+ .physExisting[hidden] + .physWhy{display:none;}
296
312
  @media (max-width:560px){
297
313
  .setRow{grid-template-columns:minmax(0,1fr);gap:6px 0;}
298
314
  .setRow .k{padding-top:0;}
@@ -1600,14 +1616,15 @@ summary{min-height:24px;padding:3px 0;}
1600
1616
  </div>
1601
1617
  </section>
1602
1618
 
1603
- <!-- 4 · check what we set up: every prefilled answer is a row the founder
1604
- confirms ("Looks right") or changes in place. Change opens the step's own
1605
- controls, moved here whole, so every handler and id is the one it always was;
1606
- "Use this" checks the row the way its old step did and confirms it. Continue
1607
- stays locked until every row that applies is confirmed. -->
1619
+ <!-- 4 · check what we set up: every prefilled answer is a one-line row the
1620
+ founder reads, and changes in place if it is wrong (task 1004550). Edit opens
1621
+ the step's own controls, moved here whole, so every handler and id is the one
1622
+ it always was; Done checks the row the way its old step did. One "Looks right,
1623
+ continue" confirms every row at once, and stops on the first row that fails
1624
+ its check, opened with its reason. -->
1608
1625
  <section class="panel" id="panel-review" aria-labelledby="rev-h">
1609
1626
  <h1 id="rev-h">Check what we set up.</h1>
1610
- <p class="lede">We filled these in from your answers. Confirm each one, or change it.</p>
1627
+ <p class="lede">We filled these in from your answers. Change anything that’s wrong.</p>
1611
1628
  <form data-next="5" id="reviewForm">
1612
1629
  <div class="setRows" id="reviewRows">
1613
1630
 
@@ -1628,15 +1645,15 @@ summary{min-height:24px;padding:3px 0;}
1628
1645
  <p class="physWhy" data-why="existing_work" hidden></p>
1629
1646
  <div class="choices" role="group" aria-label="Starting point">
1630
1647
  <button type="button" class="choice" id="c-green" aria-pressed="true">
1631
- <b>A new GitHub repo</b>
1632
- <p>An empty <strong>public</strong> repo, set up for you.</p>
1648
+ <b>A new repo</b>
1649
+ <p>Public, set up for you</p>
1633
1650
  </button>
1634
1651
  <button type="button" class="choice" id="c-adopt" aria-pressed="false">
1635
- <b>A repo I already have</b>
1636
- <p>Public or private, we never change it.</p>
1652
+ <b>A repo I have</b>
1653
+ <p>Public or private</p>
1637
1654
  </button>
1638
1655
  </div>
1639
- <div class="reassure" id="adoptNote">Nothing is overwritten. You see any conflicts first, and your open issues become tasks.</div>
1656
+ <div class="reassure" id="adoptNote">Nothing is overwritten. You see conflicts first, and open issues become tasks.</div>
1640
1657
  <!-- GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099.
1641
1658
  Without repo access we fall back to the manual owner/repo inputs
1642
1659
  (#manualHome), which stay authoritative. -->
@@ -1652,14 +1669,14 @@ summary{min-height:24px;padding:3px 0;}
1652
1669
  <div id="ghList" class="ghlist" role="group" aria-label="Your repositories"></div>
1653
1670
  <div class="hint" id="ghAdoptHint">&nbsp;</div>
1654
1671
  <!-- visibility stated on EVERY repo path (task 1002721) -->
1655
- <div class="hint">We never change a repo’s visibility — public stays public, private stays private.</div>
1672
+ <div class="hint">We never change it: public stays public, private stays private.</div>
1656
1673
  </div>
1657
1674
  <div id="ghFresh" class="wizField" hidden>
1658
1675
  <span>New repository name</span>
1659
1676
  <input type="text" id="ghNewName" placeholder="moonbase" autocomplete="off" maxlength="100" aria-label="New repository name">
1660
1677
  <!-- visibility is stated on EVERY repo path (task 1002721); updateFreshPreview()
1661
1678
  replaces this floor with the same claim plus the resolved repo URL -->
1662
- <div class="hint" id="ghFreshHint">We’ll create an empty <strong>public</strong> repo — projects here are open by design. Want private code? Create the repo yourself on GitHub and “adopt” it instead — a private repository gets its own read-only deploy key automatically.</div>
1679
+ <div class="hint" id="ghFreshHint">A new <strong>public</strong> repo. For private code, pick “A repo I have”.</div>
1663
1680
  </div>
1664
1681
  <div class="row2" id="manualHome">
1665
1682
  <label class="wizField"><span>GitHub owner <small>(user or org)</small></span>
@@ -1669,13 +1686,12 @@ summary{min-height:24px;padding:3px 0;}
1669
1686
  <input type="text" id="f-repo" placeholder="moonbase" autocomplete="off" maxlength="120">
1670
1687
  </label>
1671
1688
  <!-- visibility stated BEFORE GitHub's own radio is the first place it appears (task 1002721) -->
1672
- <div class="hint" style="grid-column:1 / -1;">Creating the repo yourself on GitHub? Public or private is your choice there — both work here, and we never change it.</div>
1689
+ <div class="hint" style="grid-column:1 / -1;">Public or private both work, and we never change it.</div>
1673
1690
  </div>
1674
1691
  <div class="hint" id="h-home">&nbsp;</div>
1675
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1676
1692
  </div>
1677
1693
  </div>
1678
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1694
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1679
1695
  </div>
1680
1696
 
1681
1697
  <!-- the address (tasks 1002704, 1002898 N8, PS19): the assigned address is
@@ -1705,10 +1721,9 @@ summary{min-height:24px;padding:3px 0;}
1705
1721
  <span>No address yet. Sign-in can’t be switched on until it has one.</span>
1706
1722
  </label>
1707
1723
  </div>
1708
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1709
1724
  </div>
1710
1725
  </div>
1711
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1726
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1712
1727
  </div>
1713
1728
 
1714
1729
  <!-- where the app runs (tasks 1004351, 1004352; ADR 0345): the hall is ours to
@@ -1731,9 +1746,9 @@ summary{min-height:24px;padding:3px 0;}
1731
1746
  <span id="appRenderWhat">We set it up on your own Render account. Render bills you directly.</span></span>
1732
1747
  </label>
1733
1748
  </fieldset>
1734
- <p class="renderWhy" id="renderLater" role="status" hidden>Your new repo has no app yet, so there is nothing for Render to run. Once your builders write it, set it up from your project’s page. Nothing is created on Render now.</p>
1749
+ <p class="renderWhy" id="renderLater" role="status" hidden>Your new repo has no app yet, so nothing is created on Render now. Set it up from your project’s page once there is one.</p>
1735
1750
  <div class="renderSetup" id="renderSetup" hidden>
1736
- <p class="renderWhy">Your Render key is used once, to create your app on your own Render account, and then thrown away — it is not kept, not even in this browser. Render bills you directly. A key can act on your whole Render account, so only paste it here. <a href="https://dashboard.render.com/u/settings#api-keys" target="_blank" rel="noopener noreferrer">Create a key in Render</a></p>
1751
+ <p class="renderWhy">Used once to create your app on your Render account, then thrown away — not kept, not even in this browser. A key can act on your whole Render account. Render bills you directly. <a href="https://dashboard.render.com/u/settings#api-keys" target="_blank" rel="noopener noreferrer">Create a key in Render</a></p>
1737
1752
  <div class="renderKeyRow">
1738
1753
  <label class="wizField"><span>Render API key</span>
1739
1754
  <input type="password" id="f-renderKey" autocomplete="off" spellcheck="false" maxlength="200" placeholder="rnd_…" aria-describedby="h-renderKey">
@@ -1775,10 +1790,9 @@ summary{min-height:24px;padding:3px 0;}
1775
1790
  </div>
1776
1791
  <div class="hint" id="h-render" role="status">&nbsp;</div>
1777
1792
  </div>
1778
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1779
1793
  </div>
1780
1794
  </div>
1781
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1795
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1782
1796
  </div>
1783
1797
 
1784
1798
  <!-- the extras (tasks 1002339, 1002340): the type's suggested set until the
@@ -1796,10 +1810,9 @@ summary{min-height:24px;padding:3px 0;}
1796
1810
  </div>
1797
1811
  <div class="modWhy" id="modWhy" aria-live="polite"></div>
1798
1812
  <div class="reassure" id="modCoreNote"></div>
1799
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1800
1813
  </div>
1801
1814
  </div>
1802
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1815
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1803
1816
  </div>
1804
1817
 
1805
1818
  <!-- team size (question 5, task 1004419): one person, or a team with a count
@@ -1832,10 +1845,9 @@ summary{min-height:24px;padding:3px 0;}
1832
1845
  </div>
1833
1846
  </div>
1834
1847
  </div>
1835
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1836
1848
  </div>
1837
1849
  </div>
1838
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1850
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1839
1851
  </div>
1840
1852
 
1841
1853
  <!-- rewards (question 6): intent only, never asked of a founder building
@@ -1851,10 +1863,9 @@ summary{min-height:24px;padding:3px 0;}
1851
1863
  <button type="button" class="tpill" data-phys="reward_intents" data-val="future-payouts" aria-pressed="false">Future payouts</button>
1852
1864
  </div>
1853
1865
  <ul class="physWhyList" data-why-list="reward_intents" hidden></ul>
1854
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1855
1866
  </div>
1856
1867
  </div>
1857
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1868
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1858
1869
  </div>
1859
1870
 
1860
1871
  <!-- how much we run (question 7): a hybrid or local framing opens its suite -->
@@ -1885,16 +1896,15 @@ summary{min-height:24px;padding:3px 0;}
1885
1896
  </div>
1886
1897
  <ul class="physWhyList" data-why-list="services" hidden></ul>
1887
1898
  </fieldset>
1888
- <button type="button" class="btn small rowUse" data-row-use>Use this</button>
1889
1899
  </div>
1890
1900
  </div>
1891
- <span class="acts"><button type="button" class="rowOk" data-row-ok>Looks right</button><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
1901
+ <span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
1892
1902
  </div>
1893
1903
  </div>
1894
1904
  <div class="hint" id="h-review">&nbsp;</div>
1895
1905
  <div class="nav">
1896
1906
  <span></span>
1897
- <button type="submit" class="btn" id="reviewGo" disabled>Confirm 7 more</button>
1907
+ <button type="submit" class="btn" id="reviewGo">Looks right, continue</button>
1898
1908
  </div>
1899
1909
  </form>
1900
1910
  </section>
@@ -5335,7 +5345,7 @@ summary{min-height:24px;padding:3px 0;}
5335
5345
  /* Visibility stated up front (task 1002694 / idea 1000684): repos WE create are
5336
5346
  public by design (github-repos.js — open-source, capture-resistant); the
5337
5347
  private path is adopting a private repo the owner makes themselves. */
5338
- hint.className = 'hint'; hint.innerHTML = 'We’ll create an empty <strong>public</strong> repo at <code style="font-family:var(--font-mono)">github.com/' + esc(myLogin()) + '/' + esc(state.repo || 'name') + '</code> — projects here are open by design. Want private code? Create the repo yourself on GitHub and “adopt” it instead — a private repository gets its own read-only deploy key automatically.';
5348
+ hint.className = 'hint'; hint.innerHTML = 'A new <strong>public</strong> repo at <code style="font-family:var(--font-mono)">github.com/' + esc(myLogin()) + '/' + esc(state.repo || 'name') + '</code>. For private code, make the repo on GitHub and pick “A repo I have”.';
5339
5349
  }
5340
5350
  }
5341
5351
  $('ghNewName').addEventListener('input', function () { state.repo = this.value.trim(); updateFreshPreview(); saveDraft(); });
@@ -5978,12 +5988,8 @@ summary{min-height:24px;padding:3px 0;}
5978
5988
  }
5979
5989
  /* the quick checks walk to the review themselves, after the server's screen */
5980
5990
  if (step === 3) return checksAdvance();
5981
- /* the review: every row that applies confirmed, each still true */
5982
- if (step === 4) {
5983
- var open = unconfirmedRows();
5984
- if (open.length) { openRow(open[0]); return false; }
5985
- return true;
5986
- }
5991
+ /* the review: every row that applies confirmed at once, each still true */
5992
+ if (step === 4) return confirmAllRows();
5987
5993
  return true;
5988
5994
  }
5989
5995
 
@@ -6157,7 +6163,9 @@ summary{min-height:24px;padding:3px 0;}
6157
6163
  if (!row || rowFixed(key)) return;
6158
6164
  row.classList.add('open');
6159
6165
  row.querySelector('.opts').hidden = false;
6160
- row.querySelector('[data-row-chg]').setAttribute('aria-expanded', 'true');
6166
+ var chg = row.querySelector('[data-row-chg]');
6167
+ chg.setAttribute('aria-expanded', 'true');
6168
+ chg.textContent = 'Done';
6161
6169
  if (key === 'address') { checkSlugAvailable(); renderAddrPanel(); }
6162
6170
  if (key === 'extras') renderModules();
6163
6171
  if (key === 'code') syncHome();
@@ -6167,11 +6175,14 @@ summary{min-height:24px;padding:3px 0;}
6167
6175
  var row = rowEl(key);
6168
6176
  row.classList.remove('open');
6169
6177
  row.querySelector('.opts').hidden = true;
6170
- row.querySelector('[data-row-chg]').setAttribute('aria-expanded', 'false');
6171
- }
6172
- /* Looks right, or Use this: the row's own checks first — a row that fails opens
6173
- with its reason showing — then it is the founder's answer. The extras row turns
6174
- "the suggested set" into an answer given, a different fact from never asked. */
6178
+ var chg = row.querySelector('[data-row-chg]');
6179
+ chg.setAttribute('aria-expanded', 'false');
6180
+ chg.textContent = 'Edit';
6181
+ }
6182
+ /* Done on an open row, or the page's one "Looks right, continue": the row's own
6183
+ checks first — a row that fails stays open with its reason showing — then it is
6184
+ the founder's answer. The extras row turns "the suggested set" into an answer
6185
+ given, a different fact from never asked. */
6175
6186
  function confirmRow(key) {
6176
6187
  if (!rowValid(key)) { openRow(key); return false; }
6177
6188
  /* only once the catalog is here: without it the suggested set is unknown, and an
@@ -6181,21 +6192,54 @@ summary{min-height:24px;padding:3px 0;}
6181
6192
  closeRow(key);
6182
6193
  saveDraft();
6183
6194
  paintSetup();
6184
- var next = unconfirmedRows()[0];
6185
- var go = next ? rowEl(next).querySelector('[data-row-ok]') : $('reviewGo');
6186
- if (go && !go.disabled) go.focus({ preventScroll: true });
6187
6195
  return true;
6188
6196
  }
6197
+ /* the page's one confirmation (task 1004550): every row that applies, in order,
6198
+ through its own check; the first that fails opens with its reason and stops it */
6199
+ function confirmAllRows() {
6200
+ var rows = unconfirmedRows();
6201
+ for (var i = 0; i < rows.length; i++) {
6202
+ if (!confirmRow(rows[i])) {
6203
+ var row = rowEl(rows[i]);
6204
+ if (row && row.scrollIntoView) row.scrollIntoView({ block: 'center' });
6205
+ $('h-review').textContent = 'Fix the row that’s open, then continue.';
6206
+ $('h-review').className = 'hint err';
6207
+ return false;
6208
+ }
6209
+ }
6210
+ $('h-review').textContent = '\u00a0'; $('h-review').className = 'hint';
6211
+ return true;
6212
+ }
6213
+ /* back to the review from a later screen with rows left to confirm: show the first
6214
+ one that fails its check opened, and confirm nothing on the founder's behalf */
6215
+ function reopenReview() {
6216
+ show(4, true);
6217
+ var bad = unconfirmedRows().filter(function (k) { return !rowValid(k); })[0];
6218
+ if (bad) openRow(bad);
6219
+ }
6189
6220
  $('reviewRows').addEventListener('click', function (ev) {
6190
- var t = ev.target.closest && ev.target.closest('[data-row-ok], [data-row-chg], [data-row-use]');
6221
+ var t = ev.target.closest && ev.target.closest('[data-row-chg]');
6191
6222
  if (!t) return;
6192
6223
  var key = t.closest('.setRow').getAttribute('data-row');
6193
- if (t.hasAttribute('data-row-chg')) {
6194
- if (rowEl(key).classList.contains('open')) closeRow(key);
6195
- else { delete confirmedRows()[key]; openRow(key); paintSetup(); }
6224
+ /* Done: the row's check, then closed — or left open with its reason */
6225
+ if (rowEl(key).classList.contains('open')) {
6226
+ if (confirmRow(key)) t.focus({ preventScroll: true });
6196
6227
  return;
6197
6228
  }
6198
- confirmRow(key);
6229
+ /* Edit: one row open at a time — another open row closes if its answer holds */
6230
+ ROWS.forEach(function (k) { if (k !== key && rowEl(k).classList.contains('open') && rowValid(k)) confirmRow(k); });
6231
+ delete confirmedRows()[key]; openRow(key); paintSetup();
6232
+ });
6233
+ /* an open row's value line follows what is typed or picked under it, live — the
6234
+ controls' own handlers run first (they are on the targets), then the row repaints */
6235
+ ['input', 'change'].forEach(function (type) {
6236
+ $('reviewRows').addEventListener(type, function (ev) {
6237
+ if (ev.target.closest && ev.target.closest('.setRow.open .opts')) {
6238
+ var row = ev.target.closest('.setRow'), t = rowText(row.getAttribute('data-row'));
6239
+ row.querySelector('[data-row-v]').textContent = t.v;
6240
+ row.querySelector('[data-row-s]').textContent = t.s;
6241
+ }
6242
+ });
6199
6243
  });
6200
6244
 
6201
6245
  /* what each row says: its value and one plain line under it */
@@ -6280,15 +6324,8 @@ summary{min-height:24px;padding:3px 0;}
6280
6324
  row.classList.toggle('done', !!c[key]);
6281
6325
  row.querySelector('[data-row-v]').textContent = t.v;
6282
6326
  row.querySelector('[data-row-s]').textContent = t.s;
6283
- var ok = row.querySelector('[data-row-ok]');
6284
- ok.textContent = c[key] ? 'Confirmed' : 'Looks right';
6285
- ok.disabled = !!c[key];
6286
6327
  row.querySelector('[data-row-chg]').hidden = rowFixed(key);
6287
6328
  });
6288
- var left = unconfirmedRows().length;
6289
- var go = $('reviewGo');
6290
- go.disabled = left > 0;
6291
- go.textContent = left ? 'Confirm ' + left + ' more' : 'Continue';
6292
6329
  }
6293
6330
  /* screen 5's one line: what Create is about to make */
6294
6331
  function renderRecap() {
@@ -6382,7 +6419,7 @@ summary{min-height:24px;padding:3px 0;}
6382
6419
  project (task 1004417) */
6383
6420
  if (!state.termsAck) { show(1, true); validateStep(1); return; }
6384
6421
  /* nothing is created before every row of the review is confirmed */
6385
- if (unconfirmedRows().length) { show(4, true); validateStep(4); return; }
6422
+ if (unconfirmedRows().length) { reopenReview(); return; }
6386
6423
  btn.disabled = true; btn.textContent = 'Raising it into the sky…';
6387
6424
  ensureFreshRepo().then(function () {
6388
6425
  return fetch(API + '/provisioning/instances', {
@@ -164,17 +164,17 @@
164
164
  { "name": "the quick checks (task 1004504): a country with states asks for one, a yes to under-18s shows the age tiers, an existing entity opens the full list, and Continue reaches the review", "auth": true, "width": 1440, "url": "/projects?view=new",
165
165
  "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["select","#physRegion","US-CA"],["click","[data-phys=\"builder_geography\"][data-val=\"us-eu\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"true\"]"],["wait",200],["click","#physHaveEntity"],["wait",100],["click","[data-phys=\"entity\"][data-val=\"for-profit\"]"],["click","#physNext"],["wait",700]],
166
166
  "expect": {"visible":["#panel-review","#reviewRows .setRow[data-row=\"code\"]"],"hidden":["#panel-checks"]} },
167
- { "name": "the review is locked (task 1004504): Continue reads Confirm N more until every row is confirmed; Change opens a row in place and Use this confirms it", "auth": true, "width": 1440, "url": "/projects?view=new",
168
- "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-chg]"],["wait",200],["click","[data-phys-solo=\"many\"]"],["wait",600],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-use]"],["wait",200]],
169
- "expect": {"visible":["#panel-review","#reviewRows .setRow[data-row=\"rewards\"]","#reviewRows .setRow.done[data-row=\"team\"]"],"attr":[["#reviewGo","disabled",""]]} },
167
+ { "name": "the review (tasks 1004504, 1004550): Edit opens a row in place, Done confirms it, and Continue is the one confirmation for the rest", "auth": true, "width": 1440, "url": "/projects?view=new",
168
+ "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-chg]"],["wait",200],["click","[data-phys-solo=\"many\"]"],["wait",600],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-chg]"],["wait",200]],
169
+ "expect": {"visible":["#panel-review","#reviewRows .setRow[data-row=\"rewards\"]","#reviewRows .setRow.done[data-row=\"team\"]"]} },
170
170
  { "name": "the wizard driver (tasks 1003346 and 1004504): the fork, what, the checks, every review row confirmed (the stub grants repo access, so the new repository is named from the project; the dotless stub host takes a domain the founder owns), the look, then the filing — the done panel with the standup strip and the human steps", "auth": true, "width": 1440, "url": "/projects?view=new",
171
- "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"code\"] [data-row-ok]"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-use]"],["wait",200],["click","#reviewRows .setRow[data-row=\"app\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"extras\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"run\"] [data-row-ok]"],["wait",200],["click","#reviewGo"],["wait",500],["click","#doCreate"],["wait",1500]],
171
+ "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#reviewGo"],["wait",500],["click","#doCreate"],["wait",1500]],
172
172
  "expect": {"visible":["#panel-done","#liveProgress .prog","#liveProgress .prog .stages li.now","#humanSteps li"],"hidden":["#panel-look","#panel-review"],"text":[["#done-h","Setting up Mercury"]]} },
173
173
  { "name": "the front door at 390: the fork's two doors stack inside one pill", "auth": true, "width": 390, "url": "/projects?view=new",
174
174
  "steps": [["wait",600],["click","#termsAck"],["wait",100]],
175
175
  "expect": {"visible":["#panel-fork",".doorPill","#wizDemo","#wizStart"]} },
176
176
  { "name": "the wizard driver at 390: the review rows stack and the walk still reaches Create", "auth": true, "width": 390, "url": "/projects?view=new",
177
- "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"code\"] [data-row-ok]"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-use]"],["wait",200],["click","#reviewRows .setRow[data-row=\"app\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"extras\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-ok]"],["wait",150],["click","#reviewRows .setRow[data-row=\"run\"] [data-row-ok]"],["wait",200],["click","#reviewGo"],["wait",500]],
177
+ "steps": [["wait",600],["click","#termsAck"],["wait",100],["click","#wizStart"],["wait",400],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["click","#panel-what button[type=submit]"],["wait",400],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["click","#physNext"],["wait",700],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#reviewGo"],["wait",500]],
178
178
  "expect": {"visible":["#panel-look","#wizLook","#doCreate"],"hidden":["#panel-review"],"text":[["#look-h","Give it a look."]]} }
179
179
  ]
180
180
  }