@bongos/core 1.23.10 → 1.23.12

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 (35) hide show
  1. package/.bongos-core.json +65 -35
  2. package/docs/adr/0337-the-hub-account-is-the-person-a-hall-account-is-their-seat-in-one-project.md +1 -0
  3. package/docs/copy-inventory.md +857 -816
  4. package/docs/copy-registry.json +1517 -1091
  5. package/docs/module-api-changelog.md +4 -0
  6. package/docs/page-inventory.json +15 -3
  7. package/docs/page-readings.json +588 -576
  8. package/modules/public-landing/public/account.html +2 -1
  9. package/modules/public-landing/public/assets/hub-bar.js +4 -2
  10. package/modules/public-landing/public/community-owner-two.states.json +16 -0
  11. package/modules/public-landing/public/community-owner.states.json +16 -0
  12. package/modules/public-landing/public/community.html +124 -11
  13. package/modules/public-landing/public/community.states.json +3 -1
  14. package/modules/public-landing/public/connections-nosuggest.states.json +15 -0
  15. package/modules/public-landing/public/connections.html +23 -3
  16. package/modules/public-landing/public/connections.states.json +1 -0
  17. package/modules/public-landing/public/contact.html +2 -1
  18. package/modules/public-landing/public/guild.html +2 -1
  19. package/modules/public-landing/public/index.html +6 -2
  20. package/modules/public-landing/public/invitations.html +2 -1
  21. package/modules/public-landing/public/privacy.html +2 -1
  22. package/modules/public-landing/public/projects.html +4 -1
  23. package/modules/public-landing/public/terms.html +2 -1
  24. package/modules/ui-design/kit/fixtures/connections-nosuggest.json +12 -0
  25. package/modules/ui-design/kit/fixtures/my-projects-owner-two.json +1 -0
  26. package/modules/ui-design/kit/fixtures/my-projects-owner.json +1 -0
  27. package/package-lock.json +2 -2
  28. package/package.json +1 -1
  29. package/release-notes.json +12 -0
  30. package/src/module-api.js +1 -1
  31. package/tests/hub_account_page.mjs +7 -1
  32. package/tests/hub_community_page.mjs +149 -9
  33. package/tests/hub_connections_page.mjs +53 -4
  34. package/tests/hub_guild_page.mjs +1 -0
  35. package/tests/landing_legal_pages.mjs +7 -1
@@ -120,6 +120,7 @@
120
120
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
121
121
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
122
122
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
123
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
123
124
  </ul>
124
125
  </div>
125
126
  </div>
@@ -130,7 +131,7 @@
130
131
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
131
132
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
132
133
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
133
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
134
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
134
135
  </ul>
135
136
  </div>
136
137
  </div>
@@ -7,8 +7,9 @@
7
7
  the three footer doors (/privacy, /terms, /contact). Each page keeps the bar's
8
8
  MARKUP (real markup, pinned byte-equal to the hub's); this file is the one copy
9
9
  of what makes it work there:
10
- - the chip, filled from GET /me — signed out there is no chip and no
11
- Your-projects item, and the sign-in door takes the chip's slot;
10
+ - the chip, filled from GET /me — signed out there is no chip, no
11
+ Your-projects item and no Builders-you-may-know item, and the sign-in
12
+ door takes the chip's slot;
12
13
  - the bands' disclosure: a trigger toggles its band, opening one closes the
13
14
  other, Escape closes and returns focus to the trigger, a click outside or
14
15
  Tab out closes, the arrows walk the items, an item activated closes it;
@@ -33,6 +34,7 @@
33
34
  $('who').hidden = !me;
34
35
  $('signinTop').hidden = !!me;
35
36
  $('mineCell').hidden = !me;
37
+ Array.prototype.forEach.call(document.querySelectorAll('.knowCell'), function (c) { c.hidden = !me; });
36
38
  [['whoImg', 'whoLogin'], ['bandWhoImg', 'bandWhoLogin']].forEach(function (ids) {
37
39
  $(ids[0]).hidden = !avatar;
38
40
  if (avatar) $(ids[0]).src = avatar;
@@ -0,0 +1,16 @@
1
+ {
2
+ "_": "The community leaderboard for a builder who owns two projects (task 1002292): GET /my-projects answers Mercury and Tidepool (fixtures/my-projects-owner-two.json), so a labelled \"Recruit to\" choice sits above the rows, and picking Tidepool re-points every row's Recruit link at Tidepool's hall invite box.",
3
+ "page": "/community",
4
+ "surface": "public-landing",
5
+ "modes": ["dark"],
6
+ "modeQuery": false,
7
+ "stub": { "fixtures": { "my-projects": "my-projects-owner-two" } },
8
+ "ignoreRequests": ["/api/(gds|bongos)/me$", "/me/guild-", "/scouting$"],
9
+ "ignoreConsole": ["/api/(gds|bongos)/me", "/scouting", "\\b40[13]\\b", "Unauthorized", "Forbidden"],
10
+ "ignoreControls": [".vh"],
11
+ "states": {
12
+ "in-owner-two": { "auth": true, "actions": [["wait", 600]], "expect": { "visible": ["#boardFor", "#boardForPick"], "value": [["#boardForPick", "0"]], "count": [["#boardForPick option", 2], ["#boardList a.commRecruit", 6]], "href": [["#boardList .commRow:first-child .commRecruit", "https://mercury.example.test/builders/watch?invite=priyanair"]] } },
13
+ "in-owner-two-picked": { "auth": true, "actions": [["wait", 600], ["select", "#boardForPick", "1"], ["wait", 200]], "expect": { "value": [["#boardForPick", "1"]], "href": [["#boardList .commRow:first-child .commRecruit", "https://tidepool.example.test/builders/watch?invite=priyanair"]], "attr": [["#boardList .commRow:first-child .commRecruit", "aria-label", "Recruit Priya Nair to Tidepool (opens in a new tab)"]] } }
14
+ },
15
+ "reducedMotion": { "auth": true, "actions": [["wait", 600]] }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "_": "The community pages for a project owner (task 1002292; spec D6, owner 2026-10-27): GET /my-projects answers one owned project (fixtures/my-projects-owner.json), so every leaderboard and search row carries a Recruit link to Mercury's hall invite box with the GitHub login filled in, and a line above the rows says what it opens. The rows are the ones everyone sees.",
3
+ "page": "/community",
4
+ "surface": "public-landing",
5
+ "modes": ["dark"],
6
+ "modeQuery": false,
7
+ "stub": { "fixtures": { "my-projects": "my-projects-owner" } },
8
+ "ignoreRequests": ["/api/(gds|bongos)/me$", "/me/guild-", "/scouting$"],
9
+ "ignoreConsole": ["/api/(gds|bongos)/me", "/scouting", "\\b40[13]\\b", "Unauthorized", "Forbidden"],
10
+ "ignoreControls": [".vh"],
11
+ "states": {
12
+ "in-owner": { "auth": true, "actions": [["wait", 600]], "expect": { "visible": ["#board", "#boardFor", "#who"], "hidden": ["#find", "#recruit", "#boardFailed"], "count": [["#boardList .commRow", 6], ["#boardList a.commRecruit", 6]], "text": [["#boardFor", "Recruit opens Mercury’s hall with their name filled in, and you send the invite there."], ["#boardList .commRow:first-child .commRecruit", "Recruit"]], "href": [["#boardList .commRow:first-child .commRecruit", "https://mercury.example.test/builders/watch?invite=priyanair"]] } },
13
+ "in-owner-find": { "auth": true, "url": "/community/find", "actions": [["wait", 600], ["fill", "#findQ", "pri"], ["click", "#findBtn"], ["wait", 300]], "expect": { "visible": ["#find", "#findFor"], "hidden": ["#board", "#recruit"], "count": [["#findList .mineRow", 2], ["#findList .mineRow__actions a.commRecruit", 2]], "href": [["#findList .mineRow:first-child .commRecruit", "https://mercury.example.test/builders/watch?invite=priyanair"]] } }
14
+ },
15
+ "reducedMotion": { "auth": true, "actions": [["wait", 600]] }
16
+ }
@@ -16,6 +16,11 @@
16
16
  their own. The one viewer-relative page is the recruiter list: drawn only from a 200 of
17
17
  GET /scouting, whose door (a project owner, or project.curate) is the server's, never
18
18
  this page's (scouting-authz.js). A 401 or 403 draws no row.
19
+ THE RECRUIT DOOR (task 1002292; spec D6, owner 2026-10-27): a project OWNER (GET
20
+ /my-projects `owned`) gets a Recruit link on each leaderboard and search row. The hub
21
+ cannot read a project's project.recruit, which lives on that project (ADR 0335 D1), so
22
+ ownership stands in. The link only opens the project's own hall invite box with the
23
+ login filled in (ADR 0353); the project decides. The rows themselves never change.
19
24
  Hub-only, like /account: platform-server.js serves /community only where
20
25
  platform-identity is on. noindex until the SEO goal decides (owner, 2026-10-27).
21
26
  Server-stamped like the footer doors: {{…}} tokens filled by landingPage(). -->
@@ -69,19 +74,29 @@
69
74
  .connAv{width:36px;height:36px;border-radius:50%;flex:none;object-fit:cover;background:color-mix(in srgb,var(--ink) 12%,transparent);}
70
75
  .commRow .mineRow__name,.connWho .mineRow__name{overflow-wrap:anywhere;}
71
76
  /* the two dropdowns (the window, the search's craft): the field's pill */
72
- .commWhen select,.commFind select{flex:0 1 auto;min-height:44px;padding:0 14px;font:inherit;font-size:14.5px;color:var(--ink);
77
+ .commWhen select,.commFind select,.commFor select{flex:0 1 auto;min-height:44px;padding:0 14px;font:inherit;font-size:14.5px;color:var(--ink);
73
78
  background:var(--bg-card);border:1px solid var(--ctl-line);border-radius:var(--radius-pill);cursor:pointer;}
74
- .commWhen select:focus-visible,.commFind input:focus-visible,.commFind select:focus-visible{outline:2px solid var(--focus);outline-offset:3px;box-shadow:0 0 0 8px var(--bg);}
79
+ .commWhen select:focus-visible,.commFind input:focus-visible,.commFind select:focus-visible,.commFor select:focus-visible{outline:2px solid var(--focus);outline-offset:3px;box-shadow:0 0 0 8px var(--bg);}
75
80
  #findStatus{margin-top:8px;}
81
+ /* the Recruit door, a project owner's only (task 1002292): what it opens, or which
82
+ project it recruits to; then a fifth column after the credits, where your own row
83
+ keeps an invisible twin so every row's credits line up */
84
+ .commFor{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin:6px 0 4px;max-width:62ch;font-size:13.5px;line-height:1.5;color:var(--ink-soft);}
85
+ #findFor{margin-top:12px;}
86
+ .commRows.canRecruit .commRow{grid-template-columns:3ch 36px minmax(0,1fr) auto auto;}
87
+ .commGap{visibility:hidden;}
76
88
  /* the recruiter list, signed out: the account page's door */
77
89
  .commDoor{padding:8px 0 10px;max-width:62ch;}
78
90
  .commDoor p{margin:0 0 18px;font-size:15px;line-height:1.55;color:var(--ink-soft);}
79
91
  .commDoor .gh{width:18px;height:18px;fill:currentColor;}
80
92
  .commDoor .btn{text-transform:none;}
81
93
  @media (max-width:480px){
82
- .commRow{grid-template-columns:3ch 32px minmax(0,1fr) auto;gap:0 10px;}
94
+ .commRow,.commRows.canRecruit .commRow{grid-template-columns:3ch 32px minmax(0,1fr) auto;gap:0 10px;}
83
95
  .commRow .connAv{width:32px;height:32px;}
84
96
  .commNum{font-size:19px;}
97
+ /* no room for a fifth column: Recruit drops under the name, as a row's actions do */
98
+ .commRow .commRecruit{grid-column:3/-1;justify-self:start;margin-top:8px;}
99
+ .commGap{display:none;}
85
100
  }
86
101
  </style>
87
102
  </head>
@@ -119,6 +134,7 @@
119
134
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
120
135
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
121
136
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
137
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
122
138
  </ul>
123
139
  </div>
124
140
  </div>
@@ -129,7 +145,7 @@
129
145
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
130
146
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
131
147
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
132
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
148
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
133
149
  </ul>
134
150
  </div>
135
151
  </div>
@@ -175,6 +191,7 @@
175
191
  </div>
176
192
  </div>
177
193
  <p class="commNote" id="boardNote">{{Currency}} earned across every project, since each builder started.</p>
194
+ <div class="commFor" id="boardFor" hidden></div>
178
195
  <p class="commMsg" id="boardLoading" role="status">Reading the leaderboard…</p>
179
196
  <p class="projMsg err" id="boardFailed" role="alert" hidden></p>
180
197
  <p class="commMsg" id="boardEmpty" hidden></p>
@@ -200,6 +217,7 @@
200
217
  </select>
201
218
  <button id="findBtn" type="submit" class="btn small">Search</button>
202
219
  </form>
220
+ <div class="commFor" id="findFor" hidden></div>
203
221
  <p class="projMsg" id="findStatus" role="status" aria-live="polite"></p>
204
222
  <ul class="mineRows" id="findList"></ul>
205
223
  </section>
@@ -258,8 +276,9 @@
258
276
  var UNIT = $('boardList').getAttribute('data-unit') || 'credits';
259
277
 
260
278
  /* THREE THINGS THESE PAGES MUST NOT DO (ADR 0217 D1, ADR 0337 D4.1, ADR 0255):
261
- 1. differ for a viewer anywhere but the recruiter list — the leaderboard and the
262
- search are drawn from viewer-independent reads, and neither asks /me;
279
+ 1. differ for a viewer anywhere but the recruiter list and the Recruit door — the
280
+ leaderboard and the search rows come from viewer-independent reads, and a
281
+ project owner only gains a link on each (task 1002292, spec D6);
263
282
  2. draw a recruiter row from anything but a 200 of GET /scouting, or draw more of a
264
283
  name-only row than its name, face and login;
265
284
  3. re-rank, re-filter or re-count what the server sent — rows are drawn in the
@@ -316,6 +335,36 @@
316
335
  return arr(list).map(function (d) { return CRAFT_WORD[d] || String(d); }).join(' · ');
317
336
  }
318
337
 
338
+ // ── the Recruit door: a project owner's link on each row (task 1002292) ─────
339
+ // Who sees it is GET /my-projects' `owned` (owner, 2026-10-27): the hub cannot read a
340
+ // project's project.recruit. Where it goes is invite-notices.js hallInviteUrl's shape,
341
+ // the project's hall invite box, which only fills the name in; the project decides.
342
+ var recruit = { to: [], pick: 0, me: '' };
343
+ function originOf(raw) {
344
+ try {
345
+ var u = new URL(String(raw));
346
+ return (u.protocol === 'https:' || u.protocol === 'http:') ? u.origin : '';
347
+ } catch (e) { return ''; }
348
+ }
349
+ // `keepPlace`: a board row keeps an invisible twin on your own row, so its credits line up
350
+ function recruitCell(r, keepPlace) {
351
+ var p = recruit.to[recruit.pick];
352
+ if (!p) return null;
353
+ var login = String(r.github_login || '');
354
+ if (!login || login.toLowerCase() === recruit.me) {
355
+ if (!keepPlace) return null;
356
+ var gap = el('span', 'btn small ghost commRecruit commGap', 'Recruit');
357
+ gap.setAttribute('aria-hidden', 'true');
358
+ return gap;
359
+ }
360
+ var a = el('a', 'btn small ghost commRecruit', 'Recruit');
361
+ a.setAttribute('href', p.origin + '/builders/watch?invite=' + encodeURIComponent(login));
362
+ a.setAttribute('target', '_blank');
363
+ a.setAttribute('rel', 'noopener');
364
+ a.setAttribute('aria-label', 'Recruit ' + (r.display_name || r.handle || login) + ' to ' + p.name + ' (opens in a new tab)');
365
+ return a;
366
+ }
367
+
319
368
  // ── the leaderboard ─────────────────────────────────────────────────────────
320
369
  var board = { window: 'all', craft: '' };
321
370
  var boardSeq = 0;
@@ -337,6 +386,8 @@
337
386
  credits.appendChild(el('span', 'commNum', num(r.credits).toLocaleString()));
338
387
  credits.appendChild(el('span', 'commUnit', UNIT));
339
388
  li.appendChild(credits);
389
+ var door = recruitCell(r, true);
390
+ if (door) li.appendChild(door);
340
391
  return li;
341
392
  }
342
393
  function emptyText() {
@@ -344,8 +395,11 @@
344
395
  if (board.window === 'all') return 'No ' + who + ' on the leaderboard yet.';
345
396
  return 'No ' + who + ' earned ' + UNIT + ' in this window yet.';
346
397
  }
398
+ var boardShown = null; // the last board drawn, redrawn when the Recruit door changes
347
399
  function paintBoard(results) {
348
400
  var list = $('boardList');
401
+ boardShown = results;
402
+ list.className = 'commRows' + (recruit.to.length ? ' canRecruit' : '');
349
403
  list.textContent = '';
350
404
  results.forEach(function (r) { if (r) list.appendChild(boardRow(r)); });
351
405
  $('boardEmpty').textContent = list.children.length ? '' : emptyText();
@@ -365,6 +419,7 @@
365
419
  if (seq !== boardSeq) return; // a later pick answered first; its rows win
366
420
  $('boardLoading').hidden = true;
367
421
  if (!r.ok) {
422
+ boardShown = null;
368
423
  $('boardList').textContent = '';
369
424
  $('boardEmpty').hidden = true;
370
425
  $('boardFailed').textContent = failText(r.status, 'The leaderboard');
@@ -402,23 +457,35 @@
402
457
  if (c) main.appendChild(el('p', 'mineRow__hint', c));
403
458
  who.appendChild(main);
404
459
  li.appendChild(who);
460
+ var door = recruitCell(r, false);
461
+ if (door) {
462
+ var acts = el('div', 'mineRow__actions');
463
+ acts.appendChild(door);
464
+ li.appendChild(acts);
465
+ }
405
466
  return li;
406
467
  }
468
+ var found = null; // the last results drawn, redrawn when the Recruit door changes
469
+ function paintFound(results) {
470
+ var list = $('findList');
471
+ found = results;
472
+ list.textContent = '';
473
+ if (results) results.forEach(function (p) { if (p) list.appendChild(findRow(p)); });
474
+ }
407
475
  function find() {
408
476
  var q = String($('findQ').value || '').trim();
409
477
  var craft = $('findCraft').value || '';
410
478
  var list = $('findList');
411
- if (q.length < QUERY_MIN) { list.textContent = ''; say('Type at least ' + QUERY_MIN + ' letters of a name.', 'err'); return Promise.resolve(); }
412
- if (q.length > QUERY_MAX) { list.textContent = ''; say('A search is at most ' + QUERY_MAX + ' characters.', 'err'); return Promise.resolve(); }
479
+ if (q.length < QUERY_MIN) { paintFound(null); say('Type at least ' + QUERY_MIN + ' letters of a name.', 'err'); return Promise.resolve(); }
480
+ if (q.length > QUERY_MAX) { paintFound(null); say('A search is at most ' + QUERY_MAX + ' characters.', 'err'); return Promise.resolve(); }
413
481
  var btn = $('findBtn');
414
482
  btn.disabled = true;
415
483
  say('Searching…');
416
484
  var path = '/community/search?q=' + encodeURIComponent(q) + (craft ? '&discipline=' + encodeURIComponent(craft) : '');
417
485
  return read(path).then(function (r) {
418
486
  btn.disabled = false;
419
- list.textContent = '';
420
- if (!r.ok) { say(failText(r.status, 'The search'), 'err'); return; }
421
- arr(r.data.results).forEach(function (p) { if (p) list.appendChild(findRow(p)); });
487
+ if (!r.ok) { paintFound(null); say(failText(r.status, 'The search'), 'err'); return; }
488
+ paintFound(arr(r.data.results));
422
489
  var n = list.children.length;
423
490
  say(n ? plural(n, 'builder') + ' found.' : 'No builder by that name' + (craft ? ' in that role' : '') + '.');
424
491
  });
@@ -448,6 +515,51 @@
448
515
  });
449
516
  }
450
517
 
518
+ // ── the Recruit door's line, and the rows redrawn with it ───────────────────
519
+ function repaintRows() {
520
+ if (boardShown) paintBoard(boardShown);
521
+ if (found) paintFound(found);
522
+ }
523
+ // One project: what Recruit opens. Several: which one it recruits to, drawn once, so a
524
+ // pick redraws only the rows and the choice keeps the focus.
525
+ function paintFor(box) {
526
+ box.textContent = '';
527
+ box.hidden = false;
528
+ if (recruit.to.length === 1) {
529
+ box.textContent = 'Recruit opens ' + recruit.to[0].name + '’s hall with their name filled in, and you send the invite there.';
530
+ return;
531
+ }
532
+ var id = box.id + 'Pick';
533
+ var label = el('label', null, 'Recruit to');
534
+ label.setAttribute('for', id);
535
+ var pick = el('select', 'commForPick');
536
+ pick.id = id;
537
+ recruit.to.forEach(function (p, i) { var o = el('option', null, p.name); o.value = String(i); pick.appendChild(o); });
538
+ pick.value = String(recruit.pick);
539
+ pick.addEventListener('change', function () {
540
+ var i = Number(pick.value);
541
+ if (!recruit.to[i] || i === recruit.pick) return;
542
+ recruit.pick = i;
543
+ repaintRows();
544
+ });
545
+ box.appendChild(label);
546
+ box.appendChild(pick);
547
+ box.appendChild(el('span', null, 'Recruit opens its hall with their name filled in, and you send the invite there.'));
548
+ }
549
+ // A failed or empty read is no door at all: viewing never waits on it.
550
+ function loadOwned(me, box) {
551
+ return read('/my-projects').then(function (r) {
552
+ if (!r.ok) return;
553
+ recruit.me = String(me.github_login || '').toLowerCase();
554
+ recruit.to = arr(r.data.owned).map(function (p) {
555
+ return { name: String((p && (p.name || p.client_id)) || 'your project'), origin: originOf(p && p.origin) };
556
+ }).filter(function (p) { return p.origin; });
557
+ if (!recruit.to.length) return;
558
+ paintFor(box);
559
+ repaintRows();
560
+ });
561
+ }
562
+
451
563
  // ── the sub-page the path names: shown, named, marked current, and read ──────
452
564
  var VIEW = viewOf(window.location.pathname);
453
565
  var view = VIEWS[VIEW];
@@ -460,6 +572,7 @@
460
572
  $('signinTop').setAttribute('href', '/api/bongos/auth/web/start?return=' + view.path + '&repos=1');
461
573
  if (VIEW === 'leaderboard') loadBoard();
462
574
  if (VIEW === 'recruiters') bar.ready.then(function (me) { if (me) loadRecruit(); else showRecruit('recruitDoor'); });
575
+ else bar.ready.then(function (me) { if (me) loadOwned(me, $(VIEW === 'find' ? 'findFor' : 'boardFor')); });
463
576
  })();
464
577
  </script>
465
578
  <script src="/assets/invite-badge.js"></script>
@@ -11,7 +11,9 @@
11
11
  "out": { "auth": false, "actions": [["wait", 400]], "expect": { "visible": ["#board", "#boardList", "#boardWindow", "#signinTop", "#projTrig"], "hidden": ["#find", "#recruit", "#who", "#boardLoading", "#boardFailed", "#boardEmpty"], "count": [["#boardList .commRow", 6]], "value": [["#boardWindow", "all"]], "attr": [["#craftTabs [data-craft=\"\"]", "aria-pressed", "true"], ["#commTrig", "aria-current", "true"], ["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]], "text": [["#boardList .commRow:first-child .mineRow__name", "Priya Nair"], ["#boardList .commRow:first-child .commNum", "18,420"], ["#boardList .commRow:first-child .mineRow__hint", "212 works shipped · 64 karma"], ["#boardNote", "Credits earned across every project, since each builder started."]] } },
12
12
  "out-30d": { "auth": false, "actions": [["wait", 400], ["select", "#boardWindow", "30d"], ["wait", 300]], "expect": { "count": [["#boardList .commRow", 3]], "value": [["#boardWindow", "30d"]], "text": [["#boardList .commRow:first-child .mineRow__name", "Ada Okafor"], ["#boardNote", "Credits earned in the last 30 days, across every project."]] } },
13
13
  "out-artists": { "auth": false, "actions": [["wait", 400], ["click", "#craftTabs [data-craft=\"artist\"]"], ["wait", 300]], "expect": { "count": [["#boardList .commRow", 1]], "text": [["#boardList .commRow:first-child .mineRow__name", "Ada Okafor"], ["#boardList .commRow:first-child .commPlace", "1"]] } },
14
- "out-community-band": { "auth": false, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "count": [["#menuCommunity .bandCell", 3]], "attr": [["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]] } },
14
+ "out-community-band": { "auth": false, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "hidden": ["#menuCommunity .knowCell"], "count": [["#menuCommunity .bandCell:not([hidden])", 3]], "attr": [["#menuCommunity a[href=\"/community\"]", "aria-current", "page"]] } },
15
+ "in-community-band": { "auth": true, "actions": [["wait", 400], ["clickIfVisible", "#commTrig"], ["wait", 300]], "expect": { "count": [["#menuCommunity .bandCell:not([hidden])", 4]], "href": [["#menuCommunity .knowCell a", "/connections#connSuggest"]] } },
16
+ "in-projects-band": { "auth": true, "actions": [["wait", 400], ["click", "#projTrig"], ["wait", 300]], "expect": { "visible": ["#menuProjects"], "count": [["#menuProjects .knowCell:not([hidden])", 1]] } },
15
17
  "out-projects-band": { "auth": false, "actions": [["wait", 400], ["click", "#projTrig"], ["wait", 300]], "expect": { "visible": ["#menuProjects"], "attr": [["#menuProjects a[href=\"/community\"]", "aria-current", "page"]] } },
16
18
  "out-find": { "auth": false, "url": "/community/find", "actions": [["wait", 400]], "expect": { "visible": ["#find", "#findQ", "#findCraft", "#findBtn"], "hidden": ["#board", "#recruit"], "attr": [["#menuCommunity a[href=\"/community/find\"]", "aria-current", "page"]] } },
17
19
  "out-find-search": { "auth": false, "url": "/community/find", "actions": [["wait", 400], ["fill", "#findQ", "pri"], ["click", "#findBtn"], ["wait", 300]], "expect": { "count": [["#findList .mineRow", 2]], "text": [["#findStatus", "2 builders found."], ["#findList .mineRow:first-child .mineRow__hint", "engineer · designer"]] } },
@@ -0,0 +1,15 @@
1
+ {
2
+ "_": "The connections page with nothing to suggest, opened by the Community menu's \"Builders you may know\" item (task 1004256): the graph is fixtures/connections-nosuggest.json, so the panel stands with its one empty line instead of vanishing. Any other visit keeps \"no suggestions, no empty shell\".",
3
+ "page": "/connections",
4
+ "surface": "public-landing",
5
+ "modes": ["dark"],
6
+ "modeQuery": false,
7
+ "stub": { "fixtures": { "connections": "connections-nosuggest" } },
8
+ "ignoreRequests": ["/api/(gds|bongos)/me$", "/my-projects", "/me/guild-"],
9
+ "ignoreConsole": ["/api/(gds|bongos)/me", "\\b401\\b", "Unauthorized"],
10
+ "ignoreControls": [".vh"],
11
+ "states": {
12
+ "in-suggest-none": { "auth": true, "url": "/connections#connSuggest", "actions": [["wait", 500]], "expect": { "visible": ["#connSuggest", "#suggestNone"], "count": [["#suggestList .mineRow", 0]] } },
13
+ "in-plain-none": { "auth": true, "actions": [["wait", 500]], "expect": { "visible": ["#connBody"], "hidden": ["#connSuggest"] } }
14
+ }
15
+ }
@@ -55,6 +55,8 @@
55
55
  rows; a row with ONE button (Remove, Connect, Withdraw) keeps it beside the name */
56
56
  @media (max-width:480px){.mineRow.connOne{flex-wrap:nowrap;}.connOne .mineRow__actions{flex-basis:auto;margin-top:0;}}
57
57
  .connSub{margin:26px 0 4px;font-size:14px;font-weight:600;color:var(--ink-soft);}
58
+ /* opened as /connections#connSuggest, the panel's heading clears the fixed bar */
59
+ #connSuggest{scroll-margin-top:calc(var(--top-h) + 16px);}
58
60
  </style>
59
61
  </head>
60
62
  <body>
@@ -91,6 +93,7 @@
91
93
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
92
94
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
93
95
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
96
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
94
97
  </ul>
95
98
  </div>
96
99
  </div>
@@ -101,7 +104,7 @@
101
104
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
102
105
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
103
106
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
104
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
107
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
105
108
  </ul>
106
109
  </div>
107
110
  </div>
@@ -157,9 +160,11 @@
157
160
 
158
161
  <!-- "Builders you may know" (ADR 0202 D5, ADR 0337 D4.2): the server's own
159
162
  suggestions and their one-line reasons, rendered as they come. One panel:
160
- the hub community page links here rather than drawing a second one. -->
163
+ the Community menu's "Builders you may know" item opens it here
164
+ (#connSuggest, task 1004256) rather than drawing a second one. -->
161
165
  <section id="connSuggest" aria-labelledby="connSuggestH" hidden>
162
166
  <h2 id="connSuggestH">Builders you may know</h2>
167
+ <p class="mineEmpty" id="suggestNone" hidden>No one to suggest yet. Suggestions come from the connections and projects you have in common with other builders.</p>
163
168
  <ul class="mineRows" id="suggestList"></ul>
164
169
  </section>
165
170
 
@@ -333,7 +338,11 @@
333
338
  p.row.className += ' connOne';
334
339
  sug.appendChild(p.row);
335
340
  });
336
- $('connSuggest').hidden = !sug.children.length;
341
+ // Arriving by the Community menu's item, an empty panel says so instead of
342
+ // vanishing; any other visit keeps "no suggestions, no empty shell".
343
+ var asked = location.hash === '#connSuggest' && lists.suggestionsRead;
344
+ $('suggestNone').hidden = !!sug.children.length || !asked;
345
+ $('connSuggest').hidden = !sug.children.length && !asked;
337
346
 
338
347
  var out = $('outgoingList');
339
348
  out.textContent = '';
@@ -351,6 +360,7 @@
351
360
  $('sentH').hidden = !outgoing.length;
352
361
  }
353
362
 
363
+ var landed = false;
354
364
  function load() {
355
365
  return Promise.all([read('/connections'), read('/connections/requests'), read('/connections/suggestions')]).then(function (r) {
356
366
  var list = r[0], reqs = r[1], sugg = r[2];
@@ -365,7 +375,11 @@
365
375
  outgoing: arr(reqs.data.outgoing),
366
376
  // additive, never load-bearing: a failed suggestions read only omits that panel
367
377
  suggestions: sugg.ok ? arr(sugg.data.suggestions) : [],
378
+ suggestionsRead: sugg.ok,
368
379
  });
380
+ // the panel draws after the browser's own jump to #connSuggest, so make it once
381
+ if (!landed && location.hash === '#connSuggest' && !$('connSuggest').hidden) $('connSuggest').scrollIntoView();
382
+ landed = true;
369
383
  });
370
384
  }
371
385
 
@@ -446,6 +460,12 @@
446
460
  if (id !== 'connBody') $('connMsg').hidden = true;
447
461
  }
448
462
  function showDoor() { show('door'); }
463
+ // the menu item pressed while already here moves only the hash: answer it as an arrival
464
+ window.addEventListener('hashchange', function () {
465
+ if (location.hash !== '#connSuggest' || $('connBody').hidden) return;
466
+ landed = false;
467
+ load();
468
+ });
449
469
  bar.ready.then(function (me) {
450
470
  if (!me) { showDoor(); return; }
451
471
  load();
@@ -10,6 +10,7 @@
10
10
  "states": {
11
11
  "out": { "auth": false, "actions": [["wait", 300]], "expect": { "visible": ["#door", "#signin", "#signinTop", "#projTrig"], "hidden": ["#connBody", "#who", "#loading", "#inactive", "#readFailed"] } },
12
12
  "in": { "auth": true, "actions": [["wait", 500]], "expect": { "visible": ["#connBody", "#connAsks", "#connSuggest", "#sentH", "#askHandle", "#askBtn", "#who"], "hidden": ["#door", "#loading", "#inactive", "#readFailed", "#menuProfile"], "count": [["#incomingList .mineRow", 2], ["#connList .mineRow", 3], ["#suggestList .mineRow", 3], ["#outgoingList .mineRow", 1]], "text": [["#connCount", "3 connections."], ["#incomingList .mineRow:first-child .mineRow__name", "Priya Nair"], ["#incomingList .mineRow:first-child .connNote", "We were both on the Tidepool hall last month. Good working with you."], ["#suggestList .mineRow:first-child .mineRow__hint", "2 connections in common"], ["#outgoingList .mineRow:first-child .mineRow__hint", "Request sent"]] } },
13
+ "in-suggest-linked": { "auth": true, "url": "/connections#connSuggest", "actions": [["wait", 500]], "expect": { "visible": ["#connSuggest"], "hidden": ["#suggestNone"], "count": [["#suggestList .mineRow", 3]] } },
13
14
  "in-profile-band": { "auth": true, "actions": [["wait", 400], ["click", "#who"], ["wait", 300]], "expect": { "visible": ["#menuProfile"], "hidden": ["#menuProjects"], "text": [["#bandWhoLogin", "builder"], ["#menuProfile [aria-current=\"page\"]", "Connections"]] } },
14
15
  "in-ask-filled": { "auth": true, "actions": [["wait", 500], ["fill", "#askHandle", "nadia"], ["fill", "#askNote", "We met on the Tidepool hall."]], "expect": { "value": [["#askHandle", "nadia"], ["#askNote", "We met on the Tidepool hall."]] } }
15
16
  },
@@ -73,6 +73,7 @@
73
73
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
74
74
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
75
75
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
76
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
76
77
  </ul>
77
78
  </div>
78
79
  </div><!--apex-only:end-->
@@ -83,7 +84,7 @@
83
84
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
84
85
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
85
86
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
86
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><!--apex-only:end-->
87
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
87
88
  </ul>
88
89
  </div>
89
90
  </div>
@@ -148,6 +148,7 @@
148
148
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
149
149
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
150
150
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
151
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
151
152
  </ul>
152
153
  </div>
153
154
  </div>
@@ -158,7 +159,7 @@
158
159
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
159
160
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
160
161
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
161
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
162
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
162
163
  </ul>
163
164
  </div>
164
165
  </div>
@@ -170,6 +170,8 @@ main:focus{outline:none;box-shadow:none}
170
170
  room for it (the New account pill and the chip), so its three items fold into the
171
171
  Projects band as its last cells; above 900 those cells are not drawn */
172
172
  .bandFold{display:none}
173
+ /* no global [hidden] rule on the landing: a signed-in-only fold cell stays down when the fold shows */
174
+ .bandFold[hidden]{display:none}
173
175
  .whoSlot{display:inline-flex;align-items:center}
174
176
  .who{gap:9px}
175
177
  .who img{width:26px;height:26px;border-radius:var(--radius-pill);object-fit:cover;flex:none;border:1px solid var(--rule)}
@@ -720,6 +722,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
720
722
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
721
723
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
722
724
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
725
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
723
726
  </ul>
724
727
  </div>
725
728
  </div><!--apex-only:end-->
@@ -730,7 +733,7 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
730
733
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">sky project directory</span></li>
731
734
  <li class="bandCell" id="mineCell" hidden><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
732
735
  <li class="bandCell"><a class="bandT" href="/projects?view=new">+ Create New Project</a><span class="bandC">fresh start/fresh idea</span></li>
733
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><!--apex-only:end-->
736
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
734
737
  </ul>
735
738
  <!-- About and Docs are site pages, not project views: they live in the footer row with
736
739
  Privacy / Terms / Contact (owner, 2026-08-28; task 1003332). -->
@@ -1053,9 +1056,10 @@ composition A; landing composition v3, picked by the owner 2026-08-27. No roll,
1053
1056
  chip.appendChild(cv);
1054
1057
  slot.appendChild(chip);
1055
1058
  wireTrigger(chip);
1056
- /* a member sees the Your-projects cell of the Projects band */
1059
+ /* a member sees the Your-projects cell of the Projects band, and Builders you may know */
1057
1060
  var mine = document.getElementById('mineCell');
1058
1061
  if (mine) mine.hidden = false;
1062
+ document.querySelectorAll('.knowCell').forEach(function (c) { c.hidden = false; });
1059
1063
  });
1060
1064
  /* the sign-out anchor keeps its honest href; the click is the real POST */
1061
1065
  var signout = document.querySelector('#menuProfile a.signout');
@@ -103,6 +103,7 @@
103
103
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
104
104
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
105
105
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
106
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
106
107
  </ul>
107
108
  </div>
108
109
  </div>
@@ -113,7 +114,7 @@
113
114
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
114
115
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
115
116
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
116
- <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
117
+ <li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
117
118
  </ul>
118
119
  </div>
119
120
  </div>
@@ -72,6 +72,7 @@
72
72
  <li class="bandCell"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li>
73
73
  <li class="bandCell"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li>
74
74
  <li class="bandCell"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li>
75
+ <li class="bandCell knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li>
75
76
  </ul>
76
77
  </div>
77
78
  </div><!--apex-only:end-->
@@ -82,7 +83,7 @@
82
83
  <li class="bandCell"><a class="bandT" href="/projects?view=map&amp;sub=table">Table</a><span class="bandC">the same projects as rows</span></li>
83
84
  <li class="bandCell" id="mineCell"><a class="bandT" href="/projects?view=mine">Your projects</a><span class="bandC">the ones you own</span></li>
84
85
  <li class="bandCell"><a class="bandT" href="/projects?view=new">New project</a><span class="bandC">five questions and a home</span></li>
85
- <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><!--apex-only:end-->
86
+ <!--apex-only:start--><li class="bandCell bandFold"><a class="bandT" href="/community">Leaderboard</a><span class="bandC">who earned the most, across every project</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/find">Find a builder</a><span class="bandC">anyone building here, by name or role</span></li><li class="bandCell bandFold"><a class="bandT" href="/community/recruiters">Open to recruiters</a><span class="bandC">who is open to recruiting, for project owners</span></li><li class="bandCell bandFold knowCell" hidden><a class="bandT" href="/connections#connSuggest">Builders you may know</a><span class="bandC">connections or projects in common</span></li><!--apex-only:end-->
86
87
  </ul>
87
88
  </div>
88
89
  </div>