@bongos/core 1.24.42 → 1.24.44

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 (92) hide show
  1. package/.bongos-core.json +108 -103
  2. package/docs/copy-inventory.md +115 -165
  3. package/docs/copy-registry.json +230 -781
  4. package/docs/file-map.md +1 -1
  5. package/docs/module-api-changelog.md +4 -0
  6. package/docs/onboarding/primer.md +1 -1
  7. package/docs/page-inventory.json +10 -38
  8. package/docs/page-readings.json +528 -627
  9. package/modules/hall-ui/public/ai-studio.html +4 -4
  10. package/modules/hall-ui/public/atlas.html +4 -4
  11. package/modules/hall-ui/public/blockers.html +4 -4
  12. package/modules/hall-ui/public/board-room.html +4 -4
  13. package/modules/hall-ui/public/builders.js +22 -505
  14. package/modules/hall-ui/public/city.html +4 -4
  15. package/modules/hall-ui/public/collab.html +4 -4
  16. package/modules/hall-ui/public/commands.html +4 -4
  17. package/modules/hall-ui/public/copy-desk.html +4 -4
  18. package/modules/hall-ui/public/craft-mode.js +2 -2
  19. package/modules/hall-ui/public/deploy.html +4 -4
  20. package/modules/hall-ui/public/dom-utils.js +2 -1
  21. package/modules/hall-ui/public/goal-map.html +4 -4
  22. package/modules/hall-ui/public/goals.html +16 -4
  23. package/modules/hall-ui/public/government.html +4 -4
  24. package/modules/hall-ui/public/hall-render.js +23 -524
  25. package/modules/hall-ui/public/hall-widgets.js +11 -109
  26. package/modules/hall-ui/public/idea.html +4 -4
  27. package/modules/hall-ui/public/ideas.html +4 -4
  28. package/modules/hall-ui/public/index.html +6 -19
  29. package/modules/hall-ui/public/index.states.json +0 -33
  30. package/modules/hall-ui/public/market-watch-item.html +4 -4
  31. package/modules/hall-ui/public/market-watch-rules.html +4 -4
  32. package/modules/hall-ui/public/market-watch.html +4 -4
  33. package/modules/hall-ui/public/modules.html +4 -4
  34. package/modules/hall-ui/public/money.html +4 -4
  35. package/modules/hall-ui/public/my-agents.html +4 -4
  36. package/modules/hall-ui/public/palette.js +7 -6
  37. package/modules/hall-ui/public/primer.html +4 -4
  38. package/modules/hall-ui/public/profile-own.js +639 -0
  39. package/modules/hall-ui/public/profile.css +2 -1
  40. package/modules/hall-ui/public/profile.html +48 -5
  41. package/modules/hall-ui/public/profile.js +27 -2
  42. package/modules/hall-ui/public/profile.states.json +18 -0
  43. package/modules/hall-ui/public/project-settings.html +4 -4
  44. package/modules/hall-ui/public/roadmap.css +7 -138
  45. package/modules/hall-ui/public/roadmap.js +35 -293
  46. package/modules/hall-ui/public/roster.html +4 -4
  47. package/modules/hall-ui/public/settings.html +4 -4
  48. package/modules/hall-ui/public/shell-trail.js +2 -1
  49. package/modules/hall-ui/public/shell.js +31 -28
  50. package/modules/hall-ui/public/street.html +4 -4
  51. package/modules/hall-ui/public/studio.html +4 -4
  52. package/modules/hall-ui/public/task.html +4 -4
  53. package/modules/hall-ui/public/thinking.html +4 -4
  54. package/modules/hall-ui/public/tweak-editor.html +4 -4
  55. package/modules/hall-ui/public/watch.html +4 -4
  56. package/modules/hall-ui/public/work.html +5 -5
  57. package/modules/onboarding/founding-mode.js +2 -1
  58. package/package-lock.json +2 -2
  59. package/package.json +1 -1
  60. package/release-notes.json +12 -0
  61. package/scripts/bongos/gen-hall-sitemap.js +1 -0
  62. package/src/bongos/serve-internal.js +6 -6
  63. package/src/module-api.js +1 -1
  64. package/tests/craft_mode_nav.mjs +2 -1
  65. package/tests/curve_controls_delegation.mjs +9 -8
  66. package/tests/curve_kind_overlay.mjs +5 -5
  67. package/tests/founding_mode.mjs +5 -3
  68. package/tests/hall_acclaim_vote_control.mjs +5 -3
  69. package/tests/hall_audit.mjs +10 -6
  70. package/tests/hall_board_world.mjs +40 -26
  71. package/tests/hall_builders_page_pass.mjs +14 -5
  72. package/tests/hall_goals_band.mjs +88 -0
  73. package/tests/hall_home_ships_bounded.mjs +10 -21
  74. package/tests/hall_kit_charts.mjs +7 -5
  75. package/tests/hall_loading.mjs +2 -1
  76. package/tests/hall_nav.mjs +41 -39
  77. package/tests/hall_numbers_page.mjs +100 -0
  78. package/tests/hall_page_gate_map.mjs +5 -1
  79. package/tests/hall_palette.mjs +19 -24
  80. package/tests/hall_profile_world.mjs +7 -2
  81. package/tests/hall_reading_room.mjs +3 -2
  82. package/tests/hall_reading_world.mjs +17 -18
  83. package/tests/hall_sitemap.mjs +2 -1
  84. package/tests/helpers.mjs +8 -2
  85. package/tests/leaderboard_roles.mjs +1 -1
  86. package/tests/module_contributions.mjs +6 -4
  87. package/tests/nav_permission_atoms.mjs +4 -2
  88. package/tests/page_tweak_artist.mjs +2 -1
  89. package/tests/rank_tier_single_source.mjs +3 -0
  90. package/tests/task_visuals.mjs +3 -1
  91. package/modules/hall-ui/public/roadmap.html +0 -58
  92. package/modules/hall-ui/public/roadmap.states.json +0 -31
@@ -174,6 +174,47 @@
174
174
  </div>
175
175
  </section>
176
176
 
177
+ <!-- ============ yours: only on your own profile (task 1005050) ============ -->
178
+
179
+ <!-- Accomplishments folded into this page (owner decision 2026-11-03,
180
+ idea 1001315): what was only ever yours there lives here, and
181
+ profile-own.js draws it ONLY on the viewer's own profile. Every
182
+ section starts hidden, and so does the screen's rail key, so
183
+ someone else's profile never shows it. -->
184
+ <section class="scroll" id="rank-scroll" aria-labelledby="rank-standing-h" data-group="yours" hidden>
185
+ <h2 id="rank-standing-h" class="scroll__h">Where you stand</h2>
186
+ <div id="rank-standing-body"><div class="hall-loading" role="status">Loading…</div></div>
187
+ </section>
188
+ <section class="scroll" id="grades-scroll" aria-labelledby="marks-h" data-group="yours" hidden>
189
+ <h2 id="marks-h" class="scroll__h">Reviews</h2>
190
+ <table class="ledger" id="recent-grades"><thead><tr><th>№</th><th>Work</th><th>Score</th><th>Verdict</th><th>Reviewed</th></tr></thead>
191
+ <tbody><tr><td colspan="5" class="ledger__empty"><span class="hall-loading" role="status">Loading…</span></td></tr></tbody></table>
192
+ <p class="ledger__note" id="grades-rolling-note" hidden></p>
193
+ </section>
194
+ <section class="scroll" id="karma-scroll" aria-labelledby="karma-h" data-group="yours" hidden>
195
+ <h2 id="karma-h" class="scroll__h">Karma</h2>
196
+ <p class="scroll__lede">Ideas passed, peer votes and approvals earn karma. Shipped work earns <span data-currency-label>credits</span>.</p>
197
+ <table class="ledger" id="karma-feed"><thead><tr><th>When</th><th>Delta</th><th>Reason</th><th>Granted by</th></tr></thead>
198
+ <tbody><tr><td colspan="4" class="ledger__empty"><span class="hall-loading" role="status">Loading…</span></td></tr></tbody></table>
199
+ </section>
200
+ <section class="scroll" id="acclaim-scroll" aria-labelledby="acclaim-h" data-group="yours" hidden>
201
+ <h2 id="acclaim-h" class="scroll__h">Peer recognition</h2>
202
+ <p class="scroll__lede">Vote on others’ finished work. A vote counts toward their karma after a week.</p>
203
+ <table class="ledger" id="acclaim-feed"><thead><tr><th>Work</th><th>By</th><th>Votes</th></tr></thead>
204
+ <tbody><tr><td colspan="3" class="ledger__empty"><span class="hall-loading" role="status">Loading…</span></td></tr></tbody></table>
205
+ <div id="acclaim-pager-mount"></div>
206
+ </section>
207
+ <section class="scroll" id="analytics-scroll" aria-labelledby="curve-h" data-group="yours" hidden>
208
+ <h2 id="curve-h" class="scroll__h">Progress</h2>
209
+ <p class="scroll__lede">How your work has changed over time. <span id="curve-scope-note"></span></p>
210
+ <div class="curve" id="curve-body">
211
+ <div class="profile__placeholder" id="curve-empty" style="display:none;">Not enough shipped work yet to chart.</div>
212
+ <div class="curve__headline" id="curve-headline"></div>
213
+ <div class="curve__grid" id="curve-grid"></div>
214
+ <div class="curve__kinds" id="curve-kinds"></div>
215
+ </div>
216
+ </section>
217
+
177
218
  <!-- ============ connections: hub-only ============ -->
178
219
 
179
220
  <!-- Connections — section 6 of the profile-page spec (R20, task
@@ -205,10 +246,10 @@
205
246
 
206
247
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
207
248
  chrome exists before the page script runs. -->
208
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
209
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
210
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
211
- <script src="/builders/shell.js?v=2026-11-05-setup-gate"></script>
249
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
250
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
251
+ <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
252
+ <script src="/builders/shell.js?v=2026-11-05-goals"></script>
212
253
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
213
254
  <script src="/builders/palette.js" defer></script>
214
255
  <!-- task 1004727: the ONE karma vote control every task/idea list renders -->
@@ -237,6 +278,8 @@
237
278
  what the tabs draw. Both loaded BEFORE profile.js. -->
238
279
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
239
280
  <script src="/builders/profile-crafts.js?v=2026-10-01-crafts"></script>
240
- <script src="/builders/profile.js?v=2026-10-01-roles"></script>
281
+ <!-- task 1005050: the "Just you" screen, drawn only on your own profile. -->
282
+ <script src="/builders/profile-own.js?v=2026-11-05-own"></script>
283
+ <script src="/builders/profile.js?v=2026-11-05-own"></script>
241
284
  </body>
242
285
  </html>
@@ -862,13 +862,21 @@
862
862
  { id: 'works', label: 'Works' },
863
863
  { id: 'activity', label: 'Activity' },
864
864
  { id: 'connections', label: 'Connections' },
865
+ // task 1005050: Accomplishments' private half, offered on your own profile only.
866
+ { id: 'yours', label: 'Just you' },
865
867
  ];
866
868
  const RAIL_GROUPS = RAIL_ITEMS.map((i) => i.id);
867
869
  let rail = null;
868
870
 
871
+ // True once render() has drawn the "Just you" screen — the viewer's own profile.
872
+ let ownShown = false;
873
+ // Whether the profile asked for is the viewer's own: /profile with no id, or an
874
+ // ?id= equal to the viewer's. Settled in load() from the REQUEST, before any
875
+ // profile data is read, so someone else's profile can never count as yours.
876
+ let ownRequest = false;
869
877
  function railItems() {
870
878
  const conn = $('#conn-scroll');
871
- return RAIL_ITEMS.filter((i) => i.id !== 'connections' || (conn && !conn.hidden));
879
+ return RAIL_ITEMS.filter((i) => (i.id !== 'connections' || (conn && !conn.hidden)) && (i.id !== 'yours' || ownShown));
872
880
  }
873
881
 
874
882
  function activateGroup(group, opts) {
@@ -877,6 +885,8 @@
877
885
  if (!groups) return;
878
886
  groups.dataset.active = group;
879
887
  rail?.activate(group);
888
+ // task 1005050: the "Just you" screen's feeds load the first time it opens.
889
+ if (group === 'yours' && window.OTBProfileOwn && window.OTBProfileOwn.open) window.OTBProfileOwn.open();
880
890
  if (!opts || opts.scroll !== false) window.scrollTo({ top: 0 });
881
891
  }
882
892
 
@@ -963,6 +973,18 @@
963
973
  // reveals its own section or leaves it hidden. Optional by design: a page
964
974
  // that does not load it simply has no connections section.
965
975
  if (window.OTBConnections) window.OTBConnections.render(data, selfId);
976
+ // task 1005050: what only you see (Accomplishments, folded in) — your own
977
+ // profile only. Someone else's profile never calls it, so its screen and
978
+ // rail key stay hidden. The data is the viewer's own /me and public feeds.
979
+ if (ownRequest && selfId != null && selfMe && window.OTBProfileOwn) {
980
+ window.OTBProfileOwn.render({ api, API, me: selfMe });
981
+ ownShown = true;
982
+ if (rail) {
983
+ rail.refresh(railItems());
984
+ rail.activate($('#profile-groups')?.dataset.active || 'overview');
985
+ }
986
+ applyHash(); // an old Accomplishments link lands here as #yours
987
+ }
966
988
  }
967
989
 
968
990
  // Render the friendly "no builder chosen" empty state for a signed-out visitor
@@ -1025,7 +1047,9 @@
1025
1047
  const idParam = new URLSearchParams(location.search).get('id');
1026
1048
  try {
1027
1049
  if (idParam) {
1028
- await fetchProfile(idParam, await resolveSelfId());
1050
+ const selfId = await resolveSelfId();
1051
+ ownRequest = selfId != null && String(idParam) === String(selfId);
1052
+ await fetchProfile(idParam, selfId);
1029
1053
  return;
1030
1054
  }
1031
1055
  // No id — soft-resolve the viewer's OWN id from /me (no hard redirect; a
@@ -1043,6 +1067,7 @@
1043
1067
  renderEmpty();
1044
1068
  return;
1045
1069
  }
1070
+ ownRequest = true;
1046
1071
  await fetchProfile(selfId, selfId);
1047
1072
  } catch (err) {
1048
1073
  console.error('[profile] failed to load', err);
@@ -73,6 +73,24 @@
73
73
  ]
74
74
  }
75
75
  },
76
+ "yours": {
77
+ "_": "Your own profile's \"Just you\" screen (task 1005050): Accomplishments' private half — where you stand, reviews, karma, peer recognition, progress.",
78
+ "auth": true,
79
+ "url": "/profile#yours",
80
+ "actions": [
81
+ [
82
+ "wait",
83
+ 1500
84
+ ]
85
+ ],
86
+ "expect": {
87
+ "visible": [
88
+ "#profile-rail",
89
+ "#rank-scroll",
90
+ "#grades-scroll"
91
+ ]
92
+ }
93
+ },
76
94
  "activity-artist": {
77
95
  "_": "The artist's Activity tab (task 1004435): approved pages, each with its before/after. Fixtures builders__2001__profile + copy-desk__artists__2001__pages.",
78
96
  "auth": true,
@@ -74,10 +74,10 @@
74
74
 
75
75
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
76
76
 
77
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
78
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
79
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
80
- <script src="/builders/shell.js?v=2026-11-05-setup-gate"></script>
77
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
78
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
79
+ <script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
80
+ <script src="/builders/shell.js?v=2026-11-05-goals"></script>
81
81
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
82
82
  <script src="/builders/palette.js" defer></script>
83
83
  <script src="/builders/hall-kit.js"></script>
@@ -1,12 +1,14 @@
1
- /* roadmap.css — the Roadmap "command deck" (task 1002426; lifted out of the
1
+ /* roadmap.css — the version band at the top of Goals (task 1005051: the Roadmap
2
+ page folded into Goals and /roadmap redirects there). Once the Roadmap
3
+ "command deck" (task 1002426; lifted out of the
2
4
  page's inline <style> by task 1002176; rebuilt into the chrome world by task
3
5
  1003306, goal 1000081). The ?v= cache-bust is stamped automatically from this
4
6
  file's content hash at boot (src/asset-version.js).
5
7
 
6
- THE PAGE: a program-level hero, then versions GROUPED BY their real status
7
- (planning=Staged · building=In flight · frozen=Parked · shipped=Shipped),
8
- and a SUMMARIZED goal layer per version (status bar + only the goals active
9
- right now, the full list on the Goals page).
8
+ THE BAND: each version in flight (the focus version first) — its phase, name,
9
+ ring, task count and lifecycle bar — then the timeline. The program hero, the
10
+ per-version goal summaries and the staged / parked / shipped cards it drew as
11
+ a page went with the page; the goals are the list right below the band.
10
12
 
11
13
  It is a reading room by task, not by archetype: nothing here is long-form, so
12
14
  it does not load room.css. What it takes from the world is the world itself —
@@ -28,13 +30,6 @@
28
30
 
29
31
  `--line` is a WIDTH; the hairline's colour is --rule / --rule-soft. */
30
32
 
31
- body[data-page="roadmap"] {
32
- --rm-plan: color-mix(in srgb, var(--ink) 16%, var(--bg));
33
- --rm-terra-weak: color-mix(in srgb, var(--terracotta) 13%, var(--bg-card));
34
- }
35
-
36
- .rm-num { font-variant-numeric: tabular-nums; }
37
-
38
33
  /* ---- shared atoms ----
39
34
  The chips are the deck's label voice: they name a KIND, so they take the
40
35
  label tokens rather than a hand-written uppercase of their own. */
@@ -66,56 +61,11 @@ body[data-page="roadmap"] {
66
61
  .rm-ring b { position:relative; z-index:1; font-family:var(--font-display); font-size:16px; font-weight:300;
67
62
  font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
68
63
  .rm-ring b i { font-style:normal; font-size:9.5px; font-weight:400; color:var(--ink-faint); }
69
-
70
- /* goal-status bar (segmented by goal COUNT: achieved / in progress / not started) */
71
- .rm-gbar { display:flex; height:8px; border-radius:var(--radius-pill); overflow:hidden;
72
- background:var(--rule-soft); }
73
- .rm-gbar__s { height:100%; }
74
- .rm-gbar__s--ach { background:var(--ok); }
75
- .rm-gbar__s--prog { background:var(--accent); }
76
- .rm-gbar__s--plan { background:var(--rm-plan); }
77
-
78
- /* ---- program hero ----
79
- v3's figure band: one glass strip of numbers, not a tinted card. The old
80
- accent gradient spent the warm colour on something nobody can press. */
81
- .rm-hero { background:var(--glass); border:var(--line) solid var(--glass-edge);
82
- -webkit-backdrop-filter:blur(var(--glass-blur)); backdrop-filter:blur(var(--glass-blur));
83
- border-radius:var(--radius); padding:var(--sp-md); margin-bottom:var(--sp-md); }
84
- .rm-hero__top { display:grid; grid-template-columns:auto 1fr; gap:26px; align-items:center; }
85
- .rm-big { display:flex; align-items:baseline; gap:3px; }
86
- .rm-big .n { font-family:var(--font-display); font-size:52px; font-weight:300; line-height:.95;
87
- letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
88
- .rm-big .u { font-size:18px; font-weight:400; color:var(--ink-faint); }
89
- /* The cap is load-bearing — the hero's left column is `auto`, so without it the
90
- caption sizes to its content and never wraps under the figure. It is a length
91
- and not a `ch`: this is a label in the mono face, and a `ch` there is the zero
92
- glyph's width, which is the measurement that put 90 characters on the primer. */
93
- .rm-lab { font-family:var(--label-face); font-size:var(--label-size); font-weight:400;
94
- letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink-faint);
95
- margin-top:7px; max-width:8rem; }
96
- .rm-hbar { height:15px; }
97
- .rm-stats { display:flex; flex-wrap:wrap; gap:9px 24px; margin-top:14px; }
98
- .rm-stat { display:flex; flex-direction:column; gap:1px; }
99
- .rm-stat .v { font-family:var(--font-display); font-size:19px; font-weight:300;
100
- font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
101
- .rm-stat .k { font-size:11.5px; color:var(--ink-faint); }
102
- .rm-stat .v.sh { color:var(--ok); } .rm-stat .v.co { color:var(--info); } .rm-stat .v.cm { color:var(--warn); }
103
- .rm-hgoals { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-top:16px; padding-top:15px;
104
- border-top:var(--line) solid var(--rule-soft); }
105
- .rm-hgoals .glab { font-family:var(--label-face); font-size:var(--label-size); font-weight:400;
106
- letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink-faint); }
107
- .rm-hgoals .rm-gbar { width:200px; max-width:44vw; }
108
- .rm-hgoals .gleg { font-size:12.5px; color:var(--ink-soft); }
109
- .rm-hgoals .gleg b { color:var(--ink); font-weight:500; font-variant-numeric:tabular-nums; }
110
-
111
64
  /* ---- section rhythm ---- */
112
65
  .rm-sec { margin-top:var(--sp-md); }
113
66
  .rm-sec__h { display:flex; align-items:center; gap:10px; margin:0 2px 13px; }
114
67
  .rm-sec__dot { width:8px; height:8px; border-radius:50%; }
115
68
  .rm-sec__dot--flight { background:var(--ok); }
116
- .rm-sec__dot--staged { background:var(--accent); }
117
- .rm-sec__dot--parked { background:var(--ink-faint); }
118
- .rm-sec__dot--shipped { background:var(--sea); }
119
69
  .rm-sec__t { font-family:var(--label-face); font-size:var(--label-size); font-weight:400;
120
70
  letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink); }
121
71
  .rm-sec__n { font-size:11.5px; color:var(--ink-faint); font-variant-numeric:tabular-nums;
@@ -129,10 +79,6 @@ body[data-page="roadmap"] {
129
79
  .rm-card { background:var(--bg-card); border:var(--line) solid transparent;
130
80
  border-radius:var(--radius); padding:var(--sp-md); }
131
81
  .rm-card--feat { grid-column:1 / -1; }
132
- .rm-card--parked { background:var(--glass); }
133
- /* staged is the one card that IS a drawn edge, and it earns it: a dashed border
134
- is the deck's whole signal that the version is not real yet. */
135
- .rm-card--staged { background:none; border-style:dashed; border-color:var(--rule); }
136
82
  .rm-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
137
83
  .rm-name { font-family:var(--font-display); font-size:19px; font-weight:300; line-height:1.15;
138
84
  letter-spacing:-.03em; margin:9px 0 0; }
@@ -143,46 +89,8 @@ body[data-page="roadmap"] {
143
89
  .rm-cardprog { margin-top:14px; }
144
90
  .rm-count { display:flex; justify-content:space-between; gap:10px; font-size:12.5px; color:var(--ink-soft); margin-bottom:6px; }
145
91
  .rm-count b { color:var(--ink); font-weight:500; font-variant-numeric:tabular-nums; }
146
- .rm-featgrid { display:grid; grid-template-columns:1.05fr 1fr; gap:22px; align-items:start; }
147
- .rm-featgrid__l { min-width:0; }
148
92
  .rm-feat-top { display:flex; align-items:flex-start; gap:16px; }
149
93
  .rm-feat-top .rt { flex:1; min-width:0; }
150
-
151
- /* ---- goals block ---- */
152
- .rm-goals { min-width:0; }
153
- .rm-goals__frame { background:var(--glass); border:var(--line) solid var(--glass-edge);
154
- border-radius:var(--radius-sm); padding:var(--sp-sm); }
155
- .rm-goals__h { display:flex; align-items:baseline; justify-content:space-between; gap:8px; margin-bottom:10px; }
156
- .rm-goals__h .t { font-family:var(--label-face); font-size:var(--label-size); font-weight:400;
157
- letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink-faint); }
158
- .rm-goals__h .n { font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums; }
159
- .rm-gdist { display:flex; gap:12px; flex-wrap:wrap; margin-top:9px; font-size:12.5px; color:var(--ink-soft); }
160
- .rm-gdist span { display:inline-flex; align-items:center; gap:6px; }
161
- .rm-gdist i { width:9px; height:9px; border-radius:2px; }
162
- .rm-gdist i.rm-ach { background:var(--ok); } .rm-gdist i.rm-prog { background:var(--accent); } .rm-gdist i.rm-plan { background:var(--rm-plan); }
163
- .rm-gdist b { color:var(--ink); font-weight:500; font-variant-numeric:tabular-nums; }
164
- .rm-ginp { margin-top:14px; }
165
- .rm-ginp__cap { font-family:var(--label-face); font-size:var(--label-size); font-weight:400;
166
- letter-spacing:var(--label-space); text-transform:var(--label-case); color:var(--ink-faint); margin-bottom:2px; }
167
- .rm-goal { display:flex; align-items:center; gap:10px; padding:4px 0; }
168
- .rm-goal + .rm-goal { border-top:var(--line) solid var(--rule-soft); }
169
- .rm-goal__dot { flex:none; width:8px; height:8px; border-radius:50%; background:var(--accent); }
170
- /* THE 24px FLOOR, BOTH AXES (task 1003304's rule, applied here). This is a link
171
- in a row whose only height was its 13px line box plus 7px of row padding —
172
- measured 20px, and it is the deck's most-clicked target. The row's padding
173
- comes down by the same amount the link's goes up, so the target grows and the
174
- list does not re-space around it. */
175
- .rm-goal__t { flex:1; min-width:0; display:flex; align-items:center; min-height:24px; padding:3px 0;
176
- font-size:13px; color:var(--ink); text-decoration:none;
177
- overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
178
- a.rm-goal__t:hover { color:var(--accent-ink); text-decoration:underline; }
179
- .rm-goal__ready { flex:none; font-family:var(--label-face); font-size:10px; font-weight:400;
180
- letter-spacing:var(--label-space); text-transform:var(--label-case);
181
- color:var(--ok); background:var(--ok-weak); padding:3px 7px; border-radius:var(--radius-pill); }
182
- .rm-goal__meter { flex:none; width:70px; height:5px; border-radius:var(--radius-pill); background:var(--rule-soft); overflow:hidden; }
183
- .rm-goal__meter i { display:block; height:100%; background:var(--accent); }
184
- .rm-goal__n { flex:none; font-size:11.5px; color:var(--ink-soft); font-variant-numeric:tabular-nums; min-width:28px; text-align:right; }
185
- .rm-goal__seed { flex:none; font-size:11.5px; color:var(--ink-faint); }
186
94
  /* the same floor: this link measured 19px */
187
95
  .rm-gmore { display:inline-flex; align-items:center; gap:6px; min-height:24px; margin-top:10px; padding:3px 0;
188
96
  font-size:12.5px; font-weight:500; color:var(--accent-ink); text-decoration:none; }
@@ -194,49 +102,10 @@ a.rm-goal__t:hover { color:var(--accent-ink); text-decoration:underline; }
194
102
  above zero (see admissionNote). */
195
103
  .rm-gadm { font-size:12.5px; color:var(--warn); margin:10px 0 0; }
196
104
  .rm-gadm b { font-weight:600; }
197
-
198
- /* parked note + staged state */
199
- .rm-parknote { display:flex; gap:9px; font-size:12.5px; color:var(--ink-soft); background:var(--bg-card);
200
- border-radius:var(--radius-sm); padding:10px 12px; margin-top:13px; }
201
- .rm-parknote svg { flex:none; width:15px; height:15px; margin-top:1px; color:var(--ink-faint); }
202
- .rm-staged-state { display:flex; align-items:center; gap:11px; margin-top:15px; padding:12px 14px;
203
- border:var(--line) dashed var(--rule); border-radius:var(--radius-sm); }
204
- .rm-staged-state svg { flex:none; width:18px; height:18px; color:var(--accent); }
205
- .rm-staged-state .s1 { font-size:13px; font-weight:500; color:var(--ink); }
206
- .rm-staged-state .s2 { font-size:12.5px; color:var(--ink-soft); margin-top:1px; }
207
- .rm-staged-state .s2 b { color:var(--ink); font-weight:500; font-variant-numeric:tabular-nums; }
208
-
209
- /* shipped strip */
210
- .rm-shipstrip { display:flex; flex-wrap:wrap; gap:10px; }
211
- .rm-shippill { display:flex; align-items:center; gap:11px; min-height:38px; background:var(--bg-card);
212
- border:var(--line) solid transparent; border-radius:var(--radius-pill); padding:8px 15px 8px 10px; text-decoration:none; }
213
- .rm-shippill:hover { border-color:var(--rule); }
214
- .rm-shippill .ok { width:20px; height:20px; border-radius:50%; background:var(--ok-weak); color:var(--ok);
215
- display:grid; place-items:center; font-size:11px; }
216
- .rm-shippill .nm { font-size:13px; font-weight:500; color:var(--ink); }
217
- .rm-shippill .mt { font-size:11.5px; color:var(--ink-faint); font-variant-numeric:tabular-nums; }
218
-
219
105
  @media (max-width:820px) {
220
106
  .rm-grid { grid-template-columns:1fr; }
221
- .rm-featgrid { grid-template-columns:1fr; }
222
- .rm-hero__top { grid-template-columns:1fr; gap:14px; }
223
107
  }
224
108
 
225
- /* A goal row is dot + title + ready pill + meter + count on ONE line, and the
226
- title is the only flexible item — so at 320 the four fixed ones eat the row
227
- and `flex: 1; min-width: 0` resolves the title to ZERO width. Measured: a
228
- 0x26 link, which passes the 24px floor's height and fails its width, and is
229
- invisible either way. The row wraps here instead: the title takes the first
230
- line whole and the meters follow under it. */
231
- @media (max-width:400px) {
232
- .rm-goal { flex-wrap:wrap; row-gap:2px; }
233
- /* the title takes the first line whole; the meter, count and ready pill
234
- follow under it. The dot goes — it is a decorative repeat of a state the
235
- meter already carries, and left in place it would sit alone above the
236
- title on a line of its own. */
237
- .rm-goal__dot { display:none; }
238
- .rm-goal__t { flex:1 0 100%; white-space:normal; }
239
- }
240
109
  /* Focus star (task 1004551): ink-faint when off, accent when on. */
241
110
  .rm-star { margin-left:auto; font-size:17px; line-height:1; color:var(--ink-faint); background:none; border:0; padding:0 2px; }
242
111
  .rm-star--on { color:var(--accent); }