@bongos/core 1.24.82 → 1.24.83

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 (54) hide show
  1. package/.bongos-core.json +58 -58
  2. package/docs/adr/0402-helm-is-the-halls-look-and-the-hall-is-dark-only.md +4 -0
  3. package/docs/copy-inventory.md +2 -2
  4. package/docs/copy-registry.json +4 -4
  5. package/docs/module-api-changelog.md +2 -0
  6. package/docs/page-readings.json +42 -42
  7. package/modules/hall-ui/public/ai-studio.html +1 -1
  8. package/modules/hall-ui/public/atlas.html +1 -1
  9. package/modules/hall-ui/public/blockers.html +1 -1
  10. package/modules/hall-ui/public/board-room.html +1 -1
  11. package/modules/hall-ui/public/city.html +2 -2
  12. package/modules/hall-ui/public/collab.html +1 -1
  13. package/modules/hall-ui/public/commands.html +1 -1
  14. package/modules/hall-ui/public/controls.css +10 -2
  15. package/modules/hall-ui/public/copy-desk.html +1 -1
  16. package/modules/hall-ui/public/deploy.html +1 -1
  17. package/modules/hall-ui/public/goal-map.html +2 -2
  18. package/modules/hall-ui/public/goals.html +1 -1
  19. package/modules/hall-ui/public/government.html +1 -1
  20. package/modules/hall-ui/public/idea.html +1 -1
  21. package/modules/hall-ui/public/ideas.html +1 -1
  22. package/modules/hall-ui/public/index.html +2 -2
  23. package/modules/hall-ui/public/market-watch-item.html +1 -1
  24. package/modules/hall-ui/public/market-watch-rules.html +1 -1
  25. package/modules/hall-ui/public/market-watch.html +1 -1
  26. package/modules/hall-ui/public/modules.html +1 -1
  27. package/modules/hall-ui/public/money.html +1 -1
  28. package/modules/hall-ui/public/my-agents.html +1 -1
  29. package/modules/hall-ui/public/options-menu.js +20 -0
  30. package/modules/hall-ui/public/primer.html +1 -1
  31. package/modules/hall-ui/public/profile.html +1 -1
  32. package/modules/hall-ui/public/project-settings.html +1 -1
  33. package/modules/hall-ui/public/roster.html +1 -1
  34. package/modules/hall-ui/public/settings.css +113 -46
  35. package/modules/hall-ui/public/settings.html +3 -3
  36. package/modules/hall-ui/public/street.html +1 -1
  37. package/modules/hall-ui/public/studio.html +1 -1
  38. package/modules/hall-ui/public/style.css +147 -61
  39. package/modules/hall-ui/public/task.html +1 -1
  40. package/modules/hall-ui/public/thinking.html +2 -2
  41. package/modules/hall-ui/public/tweak-editor.html +1 -1
  42. package/modules/hall-ui/public/visor.css +2 -2
  43. package/modules/hall-ui/public/watch.html +1 -1
  44. package/modules/hall-ui/public/work.html +1 -1
  45. package/modules/hall-ui/records/craft-mode.md +9 -0
  46. package/modules/hall-ui/records/options-menu.md +11 -0
  47. package/package-lock.json +2 -2
  48. package/package.json +1 -1
  49. package/release-notes.json +6 -0
  50. package/src/module-api.js +1 -1
  51. package/tests/design_tokens_shared.mjs +5 -1
  52. package/tests/hall_controls.mjs +1 -1
  53. package/tests/hall_helm.mjs +103 -1
  54. package/tests/hall_topbar_320.mjs +7 -4
@@ -182,7 +182,12 @@
182
182
  --line: var(--ds-line);
183
183
  --radius: var(--ds-radius-panel);
184
184
  --radius-sm: var(--ds-radius-tile);
185
- --radius-pill: var(--ds-radius-pill);
185
+ /* HELM DRAWS NO PILL (task 1005194, ADR 0402). The name stays, because some
186
+ seventy rules across the page sheets spell it, but in the hall it is a
187
+ square corner: a field, a tag, a chip, a toggle and a toast are square
188
+ inside one hairline, and only what you press is cut (--cut-path). A thing
189
+ that must be round (a portrait in the visor) says --ds-radius-pill. */
190
+ --radius-pill: 0px;
186
191
 
187
192
  /* ---- the shell's metrics. --topbar-h stays under the kit's 80px top-bar
188
193
  floor; --sidebar-w IS the rail, because v3 pins the rail at every
@@ -1126,19 +1131,26 @@ html[data-theme="dark"] .gplate__light { display: none; }
1126
1131
  min-width: 28px;
1127
1132
  padding: 0 11px 0 9px;
1128
1133
  border: 1px solid var(--rule);
1129
- border-radius: var(--radius-pill);
1130
- background: var(--bg-card);
1134
+ border-radius: var(--press-radius);
1135
+ /* Helm (task 1005194): it is pressed, so it is cut, in the name voice; the cut
1136
+ clips an outline, so its focus is the inset ring */
1137
+ clip-path: var(--cut-path-sm);
1138
+ --focus-ring: var(--press-focus);
1139
+ background: var(--press-fill);
1131
1140
  color: var(--ink);
1132
1141
  font: inherit;
1133
- font-size: 12px;
1134
- font-weight: 500;
1142
+ font-family: var(--name-face);
1143
+ font-size: var(--ds-text-xs);
1144
+ font-weight: var(--name-weight);
1145
+ letter-spacing: var(--name-space-tight);
1146
+ text-transform: var(--name-case);
1135
1147
  line-height: 1;
1136
1148
  white-space: nowrap;
1137
1149
  flex-shrink: 0;
1138
1150
  cursor: pointer;
1139
1151
  }
1140
1152
  .upd-pill:hover { border-color: var(--ink-faint); }
1141
- .upd-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1153
+ .upd-pill:focus-visible { outline: 0; border-radius: var(--press-radius); }
1142
1154
  .upd-pill__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
1143
1155
  .upd-pill[data-face="held"] .upd-pill__dot { background: var(--ink-faint); }
1144
1156
  .upd-pill[data-face="done"] { background: var(--accent); border-color: var(--accent); color: var(--accent-on); }
@@ -1331,7 +1343,6 @@ html[data-fullscreen="on"] .upd-pill {
1331
1343
  pointer-events: auto;
1332
1344
  min-height: 36px;
1333
1345
  margin-right: 8px;
1334
- box-shadow: var(--shadow-pop);
1335
1346
  }
1336
1347
  /* task 1004430: the way back must read on ANY ground. The hall's glass is
1337
1348
  near-clear, so over the black sky in the light theme it was a dark glyph on
@@ -1343,13 +1354,22 @@ html[data-fullscreen="on"] .fullscreen-toggle {
1343
1354
  gap: 6px;
1344
1355
  padding: 0 14px 0 10px;
1345
1356
  color: var(--ink);
1346
- background: var(--bg-card);
1347
- box-shadow: 0 0 0 1px var(--rule), 0 4px 16px rgba(0, 0, 0, .35);
1348
- font-size: 13px;
1349
- font-weight: 500;
1357
+ /* Helm (task 1005194): the cut corner on the press fill inside one hairline, in
1358
+ the name voice. The fill is opaque, so it still reads on any ground. */
1359
+ background: var(--press-fill);
1360
+ border: var(--line) solid var(--rule);
1361
+ border-radius: var(--press-radius);
1362
+ clip-path: var(--cut-path-sm);
1363
+ --focus-ring: var(--press-focus);
1364
+ font-family: var(--name-face);
1365
+ font-size: var(--ds-text-xs);
1366
+ font-weight: var(--name-weight);
1367
+ letter-spacing: var(--name-space-tight);
1368
+ text-transform: var(--name-case);
1350
1369
  white-space: nowrap;
1351
1370
  }
1352
- /* A phone has no room for the words; the round button keeps its card tone. */
1371
+ html[data-fullscreen="on"] .fullscreen-toggle:focus-visible { outline: 0; border-radius: var(--press-radius); }
1372
+ /* A phone has no room for the words; the button keeps its fill. */
1353
1373
  @media (max-width: 640px) {
1354
1374
  html[data-fullscreen="on"] .fullscreen-toggle { width: 36px; padding: 0; }
1355
1375
  .fullscreen-toggle__label { display: none; }
@@ -1376,7 +1396,7 @@ html[data-embed="on"] .app-content { padding-top: 0; }
1376
1396
  z-index: var(--z-topbar);
1377
1397
  max-width: min(320px, calc(100vw - 24px));
1378
1398
  padding: 8px 12px;
1379
- border-radius: 10px;
1399
+ border-radius: var(--press-radius);
1380
1400
  background: var(--bg-card);
1381
1401
  color: var(--ink);
1382
1402
  font-size: 13px;
@@ -1443,12 +1463,12 @@ html[data-embed="on"] .app-content { padding-top: 0; }
1443
1463
  (signing out). The sprites are pixel art, so they scale by whole pixels. */
1444
1464
  .craft-sprite { display: block; image-rendering: pixelated; object-fit: contain; }
1445
1465
  .craft-switch__me { padding: 0 10px 0 4px; color: var(--ink); }
1446
- /* The chip is the figure's head: the portrait cropped round its top third. */
1466
+ /* The chip is the figure's head: the portrait cropped to its top third. */
1447
1467
  .craft-sprite--chip { width: 26px; height: 26px; border-radius: var(--radius-pill); object-fit: cover; object-position: 50% 22%; }
1448
1468
  /* Character creation: each door is the owner's portrait — the figure on its plinth
1449
1469
  in the torch-lit hall — filling the top of the door, the words beneath it. */
1450
1470
  .craft-plinth { display: block; overflow: hidden; }
1451
- .craft-sprite--door { width: 100%; height: auto; aspect-ratio: 250 / 290; transition: transform 200ms cubic-bezier(.2, .7, .3, 1); }
1471
+ .craft-sprite--door { width: 100%; height: auto; aspect-ratio: 250 / 290; transition: transform var(--ds-dur-base) var(--ds-ease); }
1452
1472
  .craft-door--character:hover .craft-sprite--door,
1453
1473
  .craft-door--character:focus-visible .craft-sprite--door { transform: scale(1.03); }
1454
1474
 
@@ -1538,6 +1558,12 @@ html.setup-gate-open { overflow: hidden; }
1538
1558
  .setup-gate__foot { margin: 24px 0 0; font-size: 14px; }
1539
1559
  .setup-gate__foot a { color: var(--ink-soft); }
1540
1560
  @media (max-width: 640px) { .setup-gate__panel { padding: 28px 20px 20px; border-radius: 18px; } }
1561
+ /* THE PICKER IN HELM (task 1005194, ADR 0402). Two screens share these rules. The session
1562
+ picker ("What are you doing now?") is a square night panel over the scrim. Character
1563
+ creation (.craft-picker--create) is a whole screen, not a box: the night itself, the
1564
+ title centred in the name voice, three tall doors, the one line at the foot. A door is
1565
+ pressable, so it is cut; the door the hall suggests is the one thing lit. A cut clips an
1566
+ outline, so a door's focus is the inset ring (--press-focus). */
1541
1567
  .craft-picker {
1542
1568
  position: fixed;
1543
1569
  inset: 0;
@@ -1545,27 +1571,36 @@ html.setup-gate-open { overflow: hidden; }
1545
1571
  display: flex;
1546
1572
  align-items: flex-start;
1547
1573
  justify-content: center;
1548
- padding: max(24px, 8vh) 16px 24px;
1574
+ padding: max(var(--ds-space-md), 8vh) var(--ds-space-sm) var(--ds-space-md);
1549
1575
  overflow-y: auto;
1550
1576
  background: var(--scrim);
1551
1577
  }
1578
+ .craft-picker--create { background: var(--bg); }
1552
1579
  .craft-picker__panel {
1553
1580
  position: relative;
1554
1581
  width: min(1120px, 100%);
1555
1582
  box-sizing: border-box;
1556
1583
  display: flex;
1557
1584
  flex-direction: column;
1558
- gap: 12px;
1559
- padding: 40px 44px 30px;
1560
- border-radius: 22px;
1585
+ gap: var(--ds-space-xs);
1586
+ padding: var(--ds-space-lg) var(--ds-space-lg) var(--ds-space-md);
1561
1587
  background: var(--bg-card);
1562
1588
  color: var(--ink);
1563
- box-shadow: 0 0 0 1px var(--glass-edge), 0 24px 64px rgba(0, 0, 0, .35);
1589
+ border: var(--line-strong) solid var(--rule);
1590
+ box-shadow: var(--ds-shadow-pop);
1591
+ }
1592
+ .craft-picker__panel--create {
1593
+ padding: 0;
1594
+ gap: var(--ds-space-sm);
1595
+ background: none;
1596
+ border: 0;
1597
+ box-shadow: none;
1598
+ text-align: center;
1564
1599
  }
1565
1600
  .craft-picker__close {
1566
1601
  position: absolute;
1567
- top: 14px;
1568
- right: 14px;
1602
+ top: var(--ds-space-sm);
1603
+ right: var(--ds-space-sm);
1569
1604
  display: inline-flex;
1570
1605
  align-items: center;
1571
1606
  justify-content: center;
@@ -1587,44 +1622,88 @@ html.setup-gate-open { overflow: hidden; }
1587
1622
  text-transform: var(--label-case);
1588
1623
  color: var(--ink-faint);
1589
1624
  }
1625
+ .craft-picker__panel--create .craft-picker__eyebrow { color: var(--ink-soft); }
1590
1626
  .craft-picker__title {
1591
1627
  margin: 0;
1592
- font-family: var(--font-display);
1593
- font-size: clamp(28px, 4vw, 40px);
1594
- font-weight: 300;
1595
- letter-spacing: -0.03em;
1628
+ font-family: var(--name-face);
1629
+ font-size: var(--ds-text-headline);
1630
+ font-weight: var(--name-weight);
1631
+ letter-spacing: var(--name-space-tight);
1632
+ text-transform: var(--name-case);
1596
1633
  line-height: 1.15;
1634
+ text-wrap: balance;
1635
+ color: var(--ink);
1597
1636
  }
1598
- .craft-picker__lede { margin: 0 0 16px; font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
1637
+ .craft-picker__panel--create .craft-picker__title { letter-spacing: var(--name-space-wide); text-shadow: var(--name-glow); }
1638
+ .craft-picker__lede { margin: 0 0 var(--ds-space-sm); font-size: var(--ds-text-xl); line-height: 1.5; color: var(--ink-soft); }
1639
+ /* character creation says its one line at the foot, under the doors; the words and the
1640
+ dialog's aria-describedby are where they were */
1641
+ .craft-picker__panel--create .craft-picker__lede { order: 3; margin: var(--ds-space-sm) 0 0; }
1642
+ .craft-picker__panel--create .craft-picker__error { order: 4; }
1599
1643
  .craft-picker__doors {
1600
1644
  display: grid;
1601
1645
  grid-template-columns: repeat(4, minmax(0, 1fr));
1602
- gap: 16px;
1646
+ gap: var(--ds-space-sm);
1603
1647
  }
1648
+ .craft-picker__panel--create .craft-picker__doors { gap: var(--ds-space-md); margin-top: var(--ds-space-md); }
1604
1649
  .craft-door {
1605
1650
  display: flex;
1606
1651
  flex-direction: column;
1607
1652
  align-items: stretch;
1608
- gap: 8px;
1609
- padding: 0 0 20px;
1653
+ gap: var(--ds-space-hair);
1654
+ padding: 0 0 var(--ds-space-md);
1610
1655
  overflow: hidden;
1611
1656
  border: 0;
1612
- border-radius: 14px;
1613
- background: var(--bg);
1614
- color: var(--ink);
1657
+ border-radius: var(--press-radius);
1658
+ clip-path: var(--cut-path);
1659
+ position: relative;
1660
+ background: var(--night-glass);
1661
+ color: var(--ink-soft);
1615
1662
  font: inherit;
1616
1663
  text-align: left;
1617
1664
  cursor: pointer;
1618
- box-shadow: inset 0 0 0 1px var(--glass-edge);
1619
- transition: transform 200ms cubic-bezier(.2, .7, .3, 1), box-shadow 200ms;
1620
- }
1621
- .craft-door:hover { transform: translateY(-3px); box-shadow: inset 0 0 0 1px var(--rule); }
1622
- .craft-door:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
1623
- .craft-door--pre { box-shadow: inset 0 0 0 2px var(--accent); }
1624
- .craft-door__head { display: flex; align-items: center; gap: 10px; padding: 10px 20px 0; }
1625
- .craft-door__icon { width: 20px; height: 20px; flex-shrink: 0; }
1626
- .craft-door__name { font-size: 20px; font-weight: 500; letter-spacing: -0.02em; }
1627
- .craft-door__line { padding: 0 20px; font-size: 14px; line-height: 1.45; color: var(--ink-soft); }
1665
+ box-shadow: inset 0 0 0 var(--line-strong) var(--rule);
1666
+ transition: background-color var(--ds-dur-fast) var(--ds-ease), box-shadow var(--ds-dur-fast) var(--ds-ease);
1667
+ }
1668
+ /* the door's edge again, over what it holds: an inset shadow sits under a portrait
1669
+ that fills the door, so the hairline, the suggested door's edge and the focus ring
1670
+ would all stop at the picture */
1671
+ .craft-door::after { content: ""; position: absolute; inset: 0; pointer-events: none; box-shadow: inherit; }
1672
+ .craft-door:hover { background: var(--glass); box-shadow: inset 0 0 0 var(--line-strong) var(--ink-faint); }
1673
+ /* the door the hall suggests: the accent's wash inside the accent's edge */
1674
+ .craft-door--pre, .craft-door--pre:hover { background: var(--accent-tint); box-shadow: inset 0 0 0 2px var(--accent); }
1675
+ .craft-door:focus-visible { outline: 0; border-radius: var(--press-radius); box-shadow: var(--press-focus); }
1676
+ .craft-door__head { display: flex; align-items: center; gap: var(--ds-space-xs); padding: var(--ds-space-xs) var(--ds-space-md) 0; }
1677
+ .craft-door__icon { width: 20px; height: 20px; flex-shrink: 0; color: var(--ink); }
1678
+ .craft-door__name {
1679
+ font-family: var(--name-face);
1680
+ font-size: var(--ds-text-4xl);
1681
+ font-weight: var(--name-weight);
1682
+ letter-spacing: var(--name-space-tight);
1683
+ text-transform: var(--name-case);
1684
+ line-height: 1;
1685
+ color: var(--ink);
1686
+ }
1687
+ .craft-door--pre .craft-door__name { font-weight: var(--name-weight-lit); }
1688
+ .craft-door__line { padding: 0 var(--ds-space-md); font-size: var(--ds-text-lg); line-height: 1.45; color: var(--ink-soft); }
1689
+ /* a character's door: the portrait fills the top under the cut, the name is the largest
1690
+ thing on it, and the door under the keyboard names the key that takes it */
1691
+ .craft-door--character { gap: var(--ds-space-xs); }
1692
+ .craft-door--character .craft-door__head { flex-wrap: wrap; padding-top: var(--ds-space-sm); }
1693
+ .craft-door--character .craft-door__name { font-size: var(--ds-text-headline); letter-spacing: var(--name-space); }
1694
+ .craft-door--character .craft-door__line { font-size: var(--ds-text-2xl); }
1695
+ .craft-door--character:focus-visible .craft-door__head::after {
1696
+ content: "Enter";
1697
+ padding: 2px var(--ds-space-hair);
1698
+ background: var(--accent);
1699
+ color: var(--accent-on);
1700
+ font-family: var(--name-face);
1701
+ font-size: var(--ds-text-md);
1702
+ font-weight: var(--name-weight-lit);
1703
+ letter-spacing: var(--label-space);
1704
+ text-transform: var(--name-case);
1705
+ line-height: 1.2;
1706
+ }
1628
1707
  .craft-art {
1629
1708
  position: relative;
1630
1709
  display: block;
@@ -1664,22 +1743,22 @@ html.setup-gate-open { overflow: hidden; }
1664
1743
  flex-wrap: wrap;
1665
1744
  align-items: center;
1666
1745
  justify-content: space-between;
1667
- gap: 12px 24px;
1668
- margin-top: 14px;
1669
- padding-top: 18px;
1670
- border-top: 1px solid var(--rule-soft);
1746
+ gap: var(--ds-space-xs) var(--ds-space-md);
1747
+ margin-top: var(--ds-space-sm);
1748
+ padding-top: var(--ds-space-sm);
1749
+ border-top: var(--line) solid var(--rule-soft);
1671
1750
  }
1672
1751
  .craft-picker__again {
1673
1752
  display: inline-flex;
1674
1753
  align-items: center;
1675
- gap: 10px;
1754
+ gap: var(--ds-space-xs);
1676
1755
  min-height: 24px;
1677
- font-size: 14px;
1756
+ font-size: var(--ds-text-md);
1678
1757
  color: var(--ink-soft);
1679
1758
  cursor: pointer;
1680
1759
  }
1681
1760
  .craft-picker__again input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); }
1682
- .craft-picker__hint { font-size: 13px; color: var(--ink-faint); }
1761
+ .craft-picker__hint { font-size: var(--ds-text-sm); color: var(--ink-faint); }
1683
1762
  .craft-picker__close:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
1684
1763
  /* task 1004685 (prototype): Governing is a held seat, so a builder with none sees
1685
1764
  three doors, not four (craft-mode.js stamps the count). */
@@ -1690,20 +1769,22 @@ html.setup-gate-open { overflow: hidden; }
1690
1769
  .craft-picker__doors { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1691
1770
  }
1692
1771
  @media (max-width: 640px) {
1693
- .craft-picker { padding: 12px; }
1694
- .craft-picker__panel { padding: 28px 18px 20px; gap: 8px; border-radius: 18px; }
1695
- .craft-picker__doors { grid-template-columns: minmax(0, 1fr); gap: 10px; }
1696
- .craft-door { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 0; padding: 0 0 14px; }
1772
+ .craft-picker { padding: var(--ds-space-xs); }
1773
+ .craft-picker--create { padding: var(--ds-space-md) var(--ds-space-xs); }
1774
+ .craft-picker__panel { padding: var(--ds-space-md) var(--ds-space-sm) var(--ds-space-sm); gap: var(--ds-space-hair); }
1775
+ .craft-picker__panel--create { padding: 0; }
1776
+ .craft-picker__doors, .craft-picker__panel--create .craft-picker__doors { grid-template-columns: minmax(0, 1fr); gap: var(--ds-space-xs); }
1777
+ .craft-door { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 0; padding: 0 0 var(--ds-space-sm); clip-path: var(--cut-path-sm); }
1697
1778
  .craft-art { flex: 0 0 100%; height: 96px; }
1698
1779
  .craft-art__city { top: -8px; }
1699
- .craft-door__head { padding: 10px 16px 0; }
1700
- .craft-door__name { font-size: 18px; }
1701
- .craft-door__line { flex: 0 0 100%; padding: 0 16px; box-sizing: border-box; }
1780
+ .craft-door__head { padding: var(--ds-space-xs) var(--ds-space-sm) 0; }
1781
+ .craft-door__line { flex: 0 0 100%; padding: 0 var(--ds-space-sm); box-sizing: border-box; }
1702
1782
  /* A phone stacks the three as rows: the portrait on the left, the words beside it. */
1703
- .craft-door.craft-door--character { display: grid; grid-template-columns: 86px minmax(0, 1fr); grid-template-rows: auto 1fr; align-content: start; gap: 4px 14px; padding: 0; }
1783
+ .craft-door.craft-door--character { display: grid; grid-template-columns: 86px minmax(0, 1fr); grid-template-rows: auto 1fr; align-content: start; gap: 4px var(--ds-space-sm); padding: 0; }
1704
1784
  .craft-plinth { grid-row: 1 / span 2; width: 86px; }
1705
- .craft-door.craft-door--character > .craft-door__head { padding: 12px 14px 0 0; }
1706
- .craft-door.craft-door--character > .craft-door__line { padding: 0 14px 12px 0; }
1785
+ .craft-door.craft-door--character > .craft-door__head { padding: var(--ds-space-xs) var(--ds-space-sm) 0 0; }
1786
+ .craft-door.craft-door--character > .craft-door__line { padding: 0 var(--ds-space-sm) var(--ds-space-xs) 0; font-size: var(--ds-text-lg); }
1787
+ .craft-door--character .craft-door__name { font-size: var(--ds-text-5xl); letter-spacing: var(--name-space-tight); }
1707
1788
  }
1708
1789
 
1709
1790
  /* THE CRAFT MODE LOOKS (task 1004495; direction docs/design/craft-mode-direction.md).
@@ -4220,10 +4301,15 @@ html[data-door="out"] #hall-main { width: 100%; }
4220
4301
  color: var(--accent-ink);
4221
4302
  background: var(--accent-tint);
4222
4303
  border: 0;
4223
- border-radius: var(--radius-pill);
4304
+ border-radius: var(--press-radius);
4305
+ /* Helm (task 1005194): a chip is pressed, so it takes the small cut and the
4306
+ inset focus ring */
4307
+ clip-path: var(--cut-path-sm);
4308
+ --focus-ring: var(--press-focus);
4224
4309
  cursor: pointer;
4225
4310
  }
4226
4311
  .chip:hover { color: var(--ink); }
4312
+ .chip:focus-visible { outline: 0; border-radius: var(--press-radius); }
4227
4313
 
4228
4314
  /* tab strip — the .setup__tab idiom in the .setup__toggle frame, promoted */
4229
4315
  /* A tab strip is hairlines, not a segmented box: one rule under the row and a
@@ -8,7 +8,7 @@
8
8
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
9
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm2">
12
12
  <!-- The record archetype (shared with idea.html) and this page's own two
13
13
  shapes. Promoted out of an inline <style> by task 1003305 — the block was
14
14
  the hall's last substantive one and sat at its hall_audit ratchet. -->
@@ -12,8 +12,8 @@
12
12
  links, injected into this head by the server like every hall page's
13
13
  (tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet).
14
14
  The template carried its own Google Fonts link for the same two faces. -->
15
- <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
16
- <link rel="stylesheet" href="/builders/visor.css?v=2026-11-10-visor">
15
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm2">
16
+ <link rel="stylesheet" href="/builders/visor.css?v=2026-11-11-helm2">
17
17
  <link rel="stylesheet" href="/builders/thinking.css?v=2026-11-10-visor">
18
18
  </head>
19
19
  <!-- THE SKY (task 1004231 / sky part 3 of 5, goal 1000095; ADR 0331, ADR 0227
@@ -10,7 +10,7 @@
10
10
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
11
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
- <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
13
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm2">
14
14
  <link rel="stylesheet" href="/builders/tweak-editor.css?v=2026-09-29-tw27-aqfix">
15
15
  </head>
16
16
  <!-- THE TWEAK EDITOR (task 1004321 / BV2.TW10, goal 1000095; ADR 0341 D4 and
@@ -38,7 +38,7 @@ html[data-game="on"] .visor:not([hidden]) {
38
38
  .visor__pill:hover { border-color: var(--ink-faint); }
39
39
  .visor__pill:focus-visible, .visor__row:focus-visible, .visor__close:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
40
40
  .visor__pill--main { left: var(--visor-inset-left); bottom: var(--visor-inset-bottom); background: var(--accent); color: var(--accent-on); border-color: var(--accent); font-weight: 500; }
41
- .visor__pill--main:hover { border-color: var(--accent-deep); }
41
+ .visor__pill--main:hover { border-color: var(--accent-lift); }
42
42
  .visor__pill--actions { right: var(--visor-inset-right); top: var(--visor-inset-top); }
43
43
  .visor__pill[hidden] { display: none; }
44
44
  .visor__dots { width: 14px; height: 4px; background: radial-gradient(circle, currentColor 1.5px, transparent 2px) 0 0 / 5px 4px repeat-x; }
@@ -72,7 +72,7 @@ html[data-game="on"] .visor:not([hidden]) {
72
72
  background: none; border: 0; border-top: var(--ds-line) solid var(--rule-soft);
73
73
  color: var(--ink); font: inherit; font-size: var(--ds-text-sm); text-align: left; text-decoration: none; cursor: pointer;
74
74
  }
75
- .visor__row:hover { color: var(--accent-deep); }
75
+ .visor__row:hover { color: var(--accent-ink); }
76
76
  .visor__row--hint { cursor: default; color: var(--ink-soft); }
77
77
  .visor__row--hint:hover { color: var(--ink-soft); }
78
78
 
@@ -11,7 +11,7 @@
11
11
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
12
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
13
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
- <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
14
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm2">
15
15
  <!-- The oversight family's sheet (task 1003469): the figure band, the group
16
16
  head, the row, the form. Then the page's own: severities, the report
17
17
  reader, the grade trend. The attention tiles + tabs come from style.css's
@@ -8,7 +8,7 @@
8
8
  <link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
9
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-view2">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm2">
12
12
  <!-- Page-local styles (task 2170) — extracted from the old inline <style>
13
13
  block per the hall placement rules; shared pager/count-pill styles now
14
14
  live in style.css's hall-kit section. -->
@@ -38,6 +38,15 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
38
38
  - **Always-present tabs widened** (owner, 2026-10-03): `ALWAYS_TABS` is Builders, Collab and Profile, so every mode keeps the You and Community groups.
39
39
  - **Governing's header tallies** (task 1004563): `applyTallies()` draws "needs you N · moving M" right after the eyebrow, Governing only, hidden at <=960px (below that they squeezed the jump button under its own label, measured at 800px). Needs you is `GET /blockers?limit=1`'s `page.total`; moving is `GET /moving` (lifecycle, tasks `active` + `confirmed`, owner 2026-10-08), a count in SQL so the page never pulls task rows. Read once per page; a figure that cannot be read is LEFT OUT, never drawn as 0. The warm dot marks needs-you only above zero. It toggles the `hidden` ATTRIBUTE, never `.hidden =` (the nav gate owns that property; `tests/craft_mode_nav.mjs`). Pinned by `tests/craft_mode_tallies.mjs`.
40
40
 
41
+ ## The pickers in Helm (task 1005194, ADR 0402)
42
+
43
+ - **Character creation is a screen, not a box**: the night itself (`.craft-picker--create` on `--bg`), the title centred in the name voice, three tall doors, and the one line at the foot. The line is the same `#craft-picker-lede` the dialog is described by; CSS `order` moves it under the doors, the markup and words are unchanged.
44
+ - **A door is pressed, so it is cut** (`--cut-path`; the small cut on a phone, where the three stack as rows). The owner's portrait fills the top of the door under the cut; the name is the largest thing on it, in the name voice. The door the hall suggests (`.craft-door--pre`) is the one thing lit: the accent wash inside the accent edge. The door under the keyboard shows the inset ring and names its key ("Enter", a CSS label, as the start screen's Start does).
45
+ - **The edge is drawn twice.** A door's hairline, the suggested edge and the focus ring are inset shadows, and a portrait that fills the door would cover them, so `.craft-door::after` repeats the door's `box-shadow` over its contents.
46
+ - **The session picker** ("What are you doing now?") shares the rules: a square night panel with the strong hairline over the scrim, the title in the name voice, cut doors. Its four scenes (`.craft-art`) are untouched.
47
+ - **Not taken from the mock:** the two outer doors' perspective tilt (pixel art resamples badly under a 3D transform), the mark above the title, and the "Lands in …" line (no such words exist; the line under each name is still `CHARACTER_LINES`).
48
+ - **Tests:** `tests/hall_helm.mjs` ("character select is a Helm screen"); `tests/character_creation.mjs` still runs the behaviour.
49
+
41
50
  ## The paintbrush (task 1004497)
42
51
 
43
52
  - **Artist carries the palette and the paintbrush** (and the lightbulb, below): the palette (a feedback doc, `page-notes.js`, record `page-notes.md`) and the paintbrush (`paintbrush.js`). Both are `TOOLS` entries in `craft-mode.js` and load their own script on first press.
@@ -13,3 +13,14 @@ Every setting and configuration is reached from one vertical, grouped menu with
13
13
  - **Left the sidebar:** My agents, Project settings, Permissions, Modules (and their glyphs). The palette's agent rows open the menu; its Government rows are gone.
14
14
  - **Tests:** `tests/hall_options_menu.mjs` (the catalogue, gates, search, addresses, both redirect maps, the embedded page, game-mode Escape); `tests/hall_fullscreen.mjs` (Escape in game mode); `tests/market_watch_pages.mjs` (the settings panel in the frame).
15
15
  - **Known:** sounds are switched off (task 1004554), so the Sound entry shows its note, not a toggle.
16
+
17
+ ## The Helm look (task 1005194, ADR 0402)
18
+
19
+ The menu is a Helm screen, written from the hall tier's tokens alone (`settings.css` types in no colour or corner for it). Words, order, addresses, keys and aria are unchanged.
20
+
21
+ - **The menu** is one night panel (`--night-glass`) closed left and right by the strong ice hairline. The search is the hall's one field (`controls.css`), on the glass. An entry is a full-width row in the name voice on a soft hairline; the open entry is the accent bar under its dark ink; a group head is an ice label. Focus is the inset ring (`--press-focus`), so it reads on the accent bar too.
22
+ - **The open screen** carries its name over the strong hairline: `options-menu.js` `nameScreen()` writes the open entry's own label into `#opt-screen` (a `<p aria-hidden="true">`; the rail's `aria-current` link and each frame's `aria-label` already say it). Settings' own sections are rows on soft hairlines, not cards, with their titles in the name voice. A frame sits under the name and still fills the column to the window's foot.
23
+ - **Full screen and game mode:** the panel runs the window's full height from the top edge and names itself (`.opt-title`, the nav's own label, hidden while the top bar is up because the bar already says it). The pull to the top edge is the 60px the shell leaves a plain page above its content (`style.css`, `data-fullscreen-plain`); if that changes, change `.opt-rail`'s `margin-top` with it.
24
+ - **Widths:** the panel is `min(--helm-panel-w, 32%)` of the content column; below 860px it stacks above the screen as before. A long label wraps inside its row.
25
+ - **Not built** (the mock shows them on a Controls screen the hall does not have): the key-binding rows, "Reset all keys", and a visible "Back to the city" button. Escape still closes the menu in game mode.
26
+ - **Tests:** `tests/hall_helm.mjs` ("the options menu is a Helm screen"); the kit states in `settings.states.json` render clean at 1440, 390 and 320.
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.82",
3
+ "version": "1.24.83",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.82",
9
+ "version": "1.24.83",
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.82",
3
+ "version": "1.24.83",
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",
@@ -11595,5 +11595,11 @@
11595
11595
  "id": "1005200",
11596
11596
  "text": "The hall now has two separate views, Game and Classic, and never mixes them. You choose one each time you sign in and can switch only in Options. Game mode stays full screen and only opens the game's places."
11597
11597
  }
11598
+ ],
11599
+ "1.24.83": [
11600
+ {
11601
+ "id": "1005194",
11602
+ "text": "The options menu and the choose-your-character screen now wear the Helm look: a night panel with wide capital rows, and three tall cut-corner doors with the real characters. Fields and tags across the hall are squared to match"
11603
+ }
11598
11604
  ]
11599
11605
  }
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.82'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.83'; // 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');
@@ -133,13 +133,17 @@ test('the landing, hub, status and raise pages link it before their own sheet',
133
133
 
134
134
  test('the hall\'s old token names still resolve — each alias names a defined --ds-* token', () => {
135
135
  const style = decomment(read('modules', 'hall-ui', 'public', 'style.css'));
136
- const want = ['--line', '--radius', '--radius-sm', '--radius-pill', '--sp-hair', '--sp-xs', '--sp-sm', '--sp-md', '--sp-lg', '--sp-xl',
136
+ const want = ['--line', '--radius', '--radius-sm', '--sp-hair', '--sp-xs', '--sp-sm', '--sp-md', '--sp-lg', '--sp-xl',
137
137
  '--shadow-pop', '--z-progress', '--z-topbar', '--z-sidebar', '--z-scrim', '--z-drawer', '--z-modal', '--z-diagram-full', '--label-size'];
138
138
  for (const n of want) {
139
139
  const m = style.match(new RegExp(`${n}\\s*:\\s*var\\((--ds-[\\w-]+)\\)`));
140
140
  assert.ok(m, `${n} is an alias onto the shared sheet`);
141
141
  assert.ok(ROOT_TOKENS[m[1]], `${n} → ${m[1]} is defined in tokens.css`);
142
142
  }
143
+ // --radius-pill left the aliases with Helm (task 1005194, ADR 0402): the hall draws no pill,
144
+ // so its tier sets the name to a square corner; the shared --ds-radius-pill is untouched.
145
+ assert.match(style, /--radius-pill: 0px;/, 'the hall has no pill');
146
+ assert.equal(ROOT_TOKENS['--ds-radius-pill'], '999px', 'the shared pill is still a pill for every other surface');
143
147
  // the four-step --space-* scale still rides the --sp-* aliases
144
148
  for (const n of ['--space-1', '--space-2', '--space-3', '--space-4']) assert.match(style, new RegExp(`${n}\\s*:\\s*var\\(--sp-`));
145
149
  });
@@ -161,7 +161,7 @@ test('primary is the 46–48px door; the row size and the text button keep the 2
161
161
  }
162
162
  const field = sharedRule('select');
163
163
  assert.ok(px(prop(field, 'min-height')) >= 24, 'the field clears the floor');
164
- assert.equal(prop(field, 'border-radius'), 'var(--radius-pill)', 'a field is a pill too');
164
+ assert.equal(prop(field, 'border-radius'), 'var(--radius-pill)', 'a field spends the pill name: a pill on the status page, square in the hall, whose tier sets --radius-pill to 0px (tests/hall_helm.mjs)');
165
165
  });
166
166
 
167
167
  // ── 3. AA, measured, in both modes ───────────────────────────────────────────