@bongos/core 1.24.47 → 1.24.49

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 (106) hide show
  1. package/.bongos-core.json +165 -110
  2. package/config/branding.neutral.json +2 -1
  3. package/docs/copy-inventory.md +1028 -1028
  4. package/docs/copy-registry.json +1448 -1448
  5. package/docs/file-map.md +1 -1
  6. package/docs/module-api-changelog.md +4 -0
  7. package/docs/page-readings.json +625 -625
  8. package/modules/hall-ui/public/ai-studio.html +2 -2
  9. package/modules/hall-ui/public/atlas.html +2 -2
  10. package/modules/hall-ui/public/blockers.html +2 -2
  11. package/modules/hall-ui/public/board-room.html +2 -2
  12. package/modules/hall-ui/public/city.html +1 -1
  13. package/modules/hall-ui/public/collab.css +3 -22
  14. package/modules/hall-ui/public/collab.html +2 -2
  15. package/modules/hall-ui/public/commands.html +2 -2
  16. package/modules/hall-ui/public/controls.css +223 -0
  17. package/modules/hall-ui/public/copy-desk.html +2 -2
  18. package/modules/hall-ui/public/deploy.html +2 -2
  19. package/modules/hall-ui/public/goal-map.html +2 -2
  20. package/modules/hall-ui/public/goals.css +4 -23
  21. package/modules/hall-ui/public/goals.html +2 -2
  22. package/modules/hall-ui/public/government.html +2 -2
  23. package/modules/hall-ui/public/hall-render.js +1 -1
  24. package/modules/hall-ui/public/idea.html +2 -2
  25. package/modules/hall-ui/public/ideas.html +2 -2
  26. package/modules/hall-ui/public/index.html +5 -5
  27. package/modules/hall-ui/public/market-watch-item.html +2 -2
  28. package/modules/hall-ui/public/market-watch-rules.html +2 -2
  29. package/modules/hall-ui/public/market-watch.html +2 -2
  30. package/modules/hall-ui/public/modules.html +2 -2
  31. package/modules/hall-ui/public/money.html +2 -2
  32. package/modules/hall-ui/public/my-agents.css +3 -25
  33. package/modules/hall-ui/public/my-agents.html +2 -2
  34. package/modules/hall-ui/public/oversight.css +3 -17
  35. package/modules/hall-ui/public/panel.css +6 -48
  36. package/modules/hall-ui/public/primer.html +2 -2
  37. package/modules/hall-ui/public/profile.html +2 -2
  38. package/modules/hall-ui/public/project-settings.html +2 -2
  39. package/modules/hall-ui/public/roster.html +2 -2
  40. package/modules/hall-ui/public/settings.html +2 -2
  41. package/modules/hall-ui/public/shell.js +1 -1
  42. package/modules/hall-ui/public/speciality-tools.js +14 -14
  43. package/modules/hall-ui/public/street.html +1 -1
  44. package/modules/hall-ui/public/studio.html +2 -2
  45. package/modules/hall-ui/public/style.css +31 -255
  46. package/modules/hall-ui/public/task.html +2 -2
  47. package/modules/hall-ui/public/thinking.html +2 -2
  48. package/modules/hall-ui/public/tweak-editor.html +2 -2
  49. package/modules/hall-ui/public/watch.html +2 -2
  50. package/modules/hall-ui/public/welcome-boot.css +3 -4
  51. package/modules/hall-ui/public/welcome-boot.js +5 -3
  52. package/modules/hall-ui/public/work.html +2 -2
  53. package/modules/public-landing/public/account.html +1 -5
  54. package/modules/public-landing/public/assets/cosmos.css +7 -6
  55. package/modules/public-landing/public/community.html +1 -5
  56. package/modules/public-landing/public/connections.html +1 -5
  57. package/modules/public-landing/public/contact.html +1 -5
  58. package/modules/public-landing/public/guild.html +1 -5
  59. package/modules/public-landing/public/index.html +5 -8
  60. package/modules/public-landing/public/invitations.html +1 -5
  61. package/modules/public-landing/public/privacy.html +1 -5
  62. package/modules/public-landing/public/projects.html +1 -5
  63. package/modules/public-landing/public/terms.html +1 -5
  64. package/modules/raise/views/gate.html +4 -3
  65. package/modules/raise/views/nda.html +2 -1
  66. package/modules/raise/views/page.html +4 -3
  67. package/modules/status-ui/public/index.html +1 -1
  68. package/modules/status-ui/public/style.css +2 -2
  69. package/modules/ui-design/public/brand/apple-touch-icon.png +0 -0
  70. package/modules/ui-design/public/brand/favicon.svg +1 -0
  71. package/modules/ui-design/public/brand/mark-body.svg +1 -0
  72. package/modules/ui-design/public/brand/mark-dark.svg +1 -0
  73. package/modules/ui-design/public/brand/mark-dot.svg +1 -0
  74. package/modules/ui-design/public/brand/mark-light.svg +1 -0
  75. package/modules/ui-design/public/brand/mark-mono.svg +1 -0
  76. package/modules/ui-design/public/brand/mark.svg +21 -0
  77. package/package-lock.json +2 -2
  78. package/package.json +1 -1
  79. package/release-notes.json +12 -0
  80. package/scripts/bongos/fitness.js +1 -2
  81. package/scripts/bongos/gen-brand.js +99 -0
  82. package/scripts/gds/gen-brand.js +7 -0
  83. package/src/bongos/platform-visibility-gate.js +6 -3
  84. package/src/bongos/prelaunch-gate.js +6 -3
  85. package/src/bongos/serve-internal.js +1 -0
  86. package/src/brand-mark.js +96 -0
  87. package/src/branding.js +2 -0
  88. package/src/hall-look.js +7 -7
  89. package/src/module-api.js +1 -1
  90. package/tests/brand_mark.mjs +195 -0
  91. package/tests/bulk_toolbar.mjs +4 -1
  92. package/tests/cloud_bongos_pack.mjs +5 -2
  93. package/tests/hall_board_world.mjs +6 -2
  94. package/tests/hall_builders_page_pass.mjs +6 -4
  95. package/tests/hall_controls.mjs +274 -0
  96. package/tests/hall_loading.mjs +8 -10
  97. package/tests/hall_oversight_world.mjs +7 -4
  98. package/tests/hall_record_world.mjs +21 -7
  99. package/tests/hall_settings_world.mjs +5 -2
  100. package/tests/loading_mark.mjs +7 -13
  101. package/tests/nav_permission_atoms.mjs +2 -1
  102. package/tests/raise.mjs +3 -1
  103. package/tests/welcome_boot.mjs +5 -2
  104. package/modules/raise/public/favicon.svg +0 -1
  105. package/modules/raise/public/logo-ink.svg +0 -1
  106. package/modules/raise/public/logo-night.svg +0 -1
@@ -36,13 +36,11 @@ test('the loader is drawn from the Bongos mark, in three sizes', () => {
36
36
  for (const sel of ['.hall-loading {', '.hall-loading::before {', '.hall-loading::after {', '.hall-loading--page {', '.hall-loading--inline {']) {
37
37
  assert.ok(LOADER.includes(sel), `${sel} is declared`);
38
38
  }
39
- // The same ring arc, core and dot the shell's brand mark draws, so the loader IS the logo.
40
- const ring = SHELL.match(/<path class="mr" d="([^"]+)"/)[1];
41
- assert.ok(LOADER.includes(`d='${ring}'`), 'the ring is the brand mark\'s arc');
42
- assert.ok(SHELL.includes('<circle class="mp" cx="100" cy="100" r="55"'), 'the brand mark\'s core');
43
- assert.ok(LOADER.includes("circle cx='100' cy='100' r='55'"), 'is the loader\'s core');
44
- assert.ok(SHELL.includes('<circle cx="156" cy="46" r="12" fill="#fb9569"/>'), 'the brand mark\'s dot');
45
- assert.ok(LOADER.includes("circle cx='156' cy='46' r='12'"), 'is the loader\'s dot');
39
+ // The shell's brand mark and the loader are cut from the one mark (task 1005088), so the
40
+ // loader IS the logo: the shell references mark.svg, the masks are its ring-and-core and dot.
41
+ assert.ok(SHELL.includes('<use href="/modules/ui-design/public/brand/mark.svg#mark"/>'), 'the brand mark is the one mark');
42
+ assert.ok(LOADER.includes('--hl-shape: url("/modules/ui-design/public/brand/mark-body.svg")'), 'the loader\'s ring and core');
43
+ assert.ok(LOADER.includes('--hl-shape: url("/modules/ui-design/public/brand/mark-dot.svg")'), 'the loader\'s dot');
46
44
  });
47
45
 
48
46
  test('it moves in CSS only, on transform and filter only, and rests on the logo', () => {
@@ -74,9 +72,9 @@ test('every colour is a token; the black in the masks is alpha, not paint', () =
74
72
  for (const p of paints) assert.match(p, /^(var\(--[a-z-]+\)|color-mix\(in srgb, var\(--ink\) \d+%, var\(--bg-card\)\))$/, `${p} is a token or a mix of one`);
75
73
  // The one accent is the dot: the live thing on a waiting page (the One Warm Thing Rule).
76
74
  assert.equal((css.match(/var\(--accent\)/g) || []).length, 1, 'the accent paints the dot alone');
77
- const masks = [...css.matchAll(/url\("data:image\/svg\+xml,([^"]+)"\)/g)].map((m) => decodeURIComponent(m[1]));
78
- assert.equal(masks.length, 2, 'two masks: the ring and core, and the dot');
79
- for (const m of masks) assert.doesNotMatch(m.replace(/stroke='black'|fill='none'/g, ''), /fill='|stroke='|#/, 'a mask carries no colour of its own');
75
+ // The two masks are the brand folder's one-ink shapes (task 1005088): only their alpha counts.
76
+ const masks = [...css.matchAll(/url\("\/modules\/ui-design\/public\/brand\/(mark-[a-z]+\.svg)"\)/g)].map((m) => m[1]);
77
+ assert.deepEqual(masks, ['mark-body.svg', 'mark-dot.svg'], 'two masks: the ring and core, and the dot');
80
78
  });
81
79
 
82
80
  test('the page loaders step aside by themselves, and never show without :has()', () => {
@@ -104,10 +104,13 @@ test('the shared confirm modal sits on --z-modal, closed by one hairline and no
104
104
  });
105
105
 
106
106
  test('a number input inside a family field clears the 24px floor', () => {
107
- const css = read('oversight.css');
108
- const i = css.indexOf('.ov-field input, .ov-field select, .ov-field textarea {');
109
- assert.ok(i > 0, 'the field rule exists');
110
- assert.match(css.slice(i, i + 500), /min-height: 30px/, 'the field restates the shell\'s 30px pill');
107
+ // task 1005084: the shared field (controls.css) reaches a number input itself,
108
+ // at 40px; the family field only stretches it to the row.
109
+ const shared = read('controls.css').replace(/\/\*[\s\S]*?\*\//g, '');
110
+ const m = shared.match(/([^{}]*input\[type="number"\][^{}]*)\{([^{}]*min-height[^{}]*)\}/);
111
+ assert.ok(m, 'the shared field rule covers a number input');
112
+ assert.ok(Number((m[2].match(/min-height:\s*(\d+)px/) || [])[1]) >= 24, 'and clears the 24px floor');
113
+ assert.match(read('oversight.css'), /\.ov-field input, \.ov-field select, \.ov-field textarea \{ width: 100%/, 'the family field stretches it');
111
114
  assert.match(read('government.html'), /id="gov-assign-builder" type="number"/, 'the builder id is still a number input');
112
115
  });
113
116
 
@@ -66,6 +66,7 @@ const read = (f) => fs.readFileSync(path.join(HALL, f), 'utf8');
66
66
 
67
67
  const styleCss = read('style.css');
68
68
  const recordCss = read('record.css');
69
+ const controlsCss = read('controls.css');
69
70
  const taskCss = read('task.css');
70
71
  const ideaCss = read('idea.css');
71
72
  const ideasCss = read('ideas.css');
@@ -83,6 +84,16 @@ const rule = (css, selector) => {
83
84
  return m ? m[2] : null;
84
85
  };
85
86
  const decomment = (css) => css.replace(/\/\*[\s\S]*?\*\//g, '');
87
+ // The body of the first rule in `css` whose selector LIST holds `selector` and
88
+ // declares `prop` (task 1005084: the shared controls.css lists the hall's button
89
+ // names together, so a name is rarely the last selector before the brace).
90
+ const ruleHolding = (css, selector, prop) => {
91
+ for (const m of css.replace(/\/\*[\s\S]*?\*\//g, '').matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
92
+ const sels = m[1].split(',').map((s) => s.trim());
93
+ if (sels.includes(selector) && new RegExp(`(^|;)\\s*${prop}\\s*:`).test(m[2])) return m[2];
94
+ }
95
+ return null;
96
+ };
86
97
 
87
98
  // ---- 1. the right rail belongs to the shell --------------------------------
88
99
 
@@ -134,30 +145,33 @@ test('the ideas composer OPTS IN, and since the fold it opts in WITH THE METER',
134
145
  // ---- 2. the button vocabulary that had no rule -----------------------------
135
146
 
136
147
  test('.btn and .btn--ghost are defined, and say what .btn-accent / .btn-ghost say', () => {
137
- const btn = rule(styleCss, '.btn');
148
+ // task 1005084 moved the hall's buttons into the shared controls.css
149
+ const btn = ruleHolding(controlsCss, '.btn', 'background');
138
150
  assert.ok(btn, '.btn has a rule — six pages rendered browser-default buttons without one');
139
151
  assert.match(btn, /background:\s*var\(--accent\)/, '.btn is the accent door');
140
152
  assert.match(btn, /color:\s*var\(--accent-on\)/, '--accent-on is the dark ink for the salmon');
141
- assert.match(btn, /border-radius:\s*var\(--radius-pill\)/, 'pill or nothing (DESIGN.md, Shapes)');
153
+ const shape = ruleHolding(controlsCss, '.btn', 'border-radius');
154
+ assert.match(shape, /border-radius:\s*var\(--radius-pill\)/, 'pill or nothing (DESIGN.md, Shapes)');
142
155
  // collab.css's .btn--quiet sets only a border-COLOUR; a modifier cannot paint
143
156
  // an edge that was never reserved, so the base has to carry a transparent one.
144
- assert.match(btn, /border:\s*var\(--line\)\s+solid\s+transparent/,
157
+ assert.match(shape, /border:\s*var\(--line\)\s+solid\s+transparent/,
145
158
  'the edge is reserved so a modifier that sets only border-color still draws');
146
- const ghost = rule(styleCss, '.btn--ghost');
159
+ const ghost = ruleHolding(controlsCss, '.btn--ghost', 'background');
147
160
  assert.ok(ghost, '.btn--ghost has a rule');
148
- assert.match(ghost, /background:\s*none/, 'the quiet sibling is a hairline pill, not a fill');
161
+ assert.match(ghost, /background:\s*transparent/, 'the quiet sibling is a hairline pill, not a fill');
162
+ assert.equal(ghost, ruleHolding(controlsCss, '.btn-ghost', 'background'), 'and .btn-ghost says the same, in the same rule');
149
163
  assert.match(ghost, /border-color:\s*var\(--rule\)/, 'and it takes the reserved edge');
150
164
  });
151
165
 
152
166
  // ---- 3. the world's own bans ------------------------------------------------
153
167
 
154
168
  test('nothing in the record family paints text white on the accent', () => {
155
- const primary = rule(styleCss, '.td-btn--primary');
169
+ const primary = ruleHolding(controlsCss, '.td-btn--primary', 'background');
156
170
  assert.ok(primary, '.td-btn--primary has a rule');
157
171
  assert.match(primary, /color:\s*var\(--accent-on\)/, 'the dark ink, not white');
158
172
  // Match white as a VALUE, not anywhere in the block: `white-space: nowrap` is
159
173
  // a property name and would be read as a colour by a bare /\bwhite\b/.
160
- for (const [name, css] of [['style.css .td-btn--primary', primary], ['record.css', decomment(recordCss)],
174
+ for (const [name, css] of [['controls.css .td-btn--primary', primary], ['record.css', decomment(recordCss)],
161
175
  ['task.css', decomment(taskCss)], ['idea.css', decomment(ideaCss)], ['ideas.css', decomment(ideasCss)]]) {
162
176
  assert.doesNotMatch(css, /(background|color):\s*(#fff\b|#ffffff\b|white\b)/i,
163
177
  `${name} paints a white literal — DESIGN.md bans white on the salmon, and every other ground has a token`);
@@ -290,11 +290,14 @@ test('white on the accent is gone, and the Discord mark is the one named excepti
290
290
  // base pill rule AND the save rule, so the save rule is found by its own name
291
291
  // and the member is asserted against it. (`.pair-approve` was its sibling here
292
292
  // until task 1003890 removed the pair page.)
293
- const save = ruleOf(panelCss, '.pbtn--save');
293
+ // task 1005084: the family's buttons are the hall's shared ones (controls.css)
294
+ const controlsCss = read('controls.css');
295
+ const saveRule = stripComments(controlsCss).match(/([^{}]*\.pbtn--save[^{}]*)\{([^{}]*background[^{}]*)\}/);
296
+ const save = saveRule && saveRule[2];
294
297
  assert.ok(save, '.pbtn--save has a rule');
295
298
  assert.match(save, /background:\s*var\(--accent\)/);
296
299
  assert.match(save, /color:\s*var\(--accent-on\)/, 'the dark ink for the salmon — white on it fails AA');
297
- const saveSelector = stripComments(panelCss).match(/([^{}]*\.pbtn--save[^{}]*)\{/);
300
+ const saveSelector = saveRule;
298
301
  assert.ok(saveSelector, 'the save rule\'s selector list is readable');
299
302
  for (const member of ['.craft-save']) {
300
303
  assert.ok(saveSelector[1].split(',').map((s) => s.trim()).includes(member), `${member} is the accent door on its page`);
@@ -38,7 +38,8 @@ const SURFACES = {
38
38
  status: { css: STATUS_CSS, loader: section(STATUS_CSS, '/* ---------- The loader (task 1005053') },
39
39
  };
40
40
  const flat = (s) => s.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\s+/g, ' ');
41
- const masksOf = (css) => [...css.matchAll(/url\("data:image\/svg\+xml,([^"]+)"\)/g)].map((m) => decodeURIComponent(m[1]));
41
+ // The masks are the brand folder's one-ink shapes (task 1005088), named by file.
42
+ const masksOf = (css) => [...css.matchAll(/url\("\/modules\/ui-design\/public\/brand\/(mark-[a-z]+\.svg)"\)/g)].map((m) => m[1]);
42
43
  function keyframes(css, name) {
43
44
  const m = css.match(new RegExp(`@keyframes ${name} ?\\{`));
44
45
  assert.ok(m, `@keyframes ${name} exists`);
@@ -48,16 +49,11 @@ function keyframes(css, name) {
48
49
  }
49
50
 
50
51
  test('the apex loader is the bar\'s own Bongos mark, and the status loader is the same mark', () => {
51
- // The apex bar draws the mark inline (account.html's .bongosMark); the loader's
52
- // two masks carry exactly its arc, core and dot, so the loader IS the logo.
52
+ // The apex bar and the loader are cut from the one mark (task 1005088): the bar references
53
+ // mark.svg, and the loader's two masks are its ring-and-core and its dot, so the loader IS the logo.
53
54
  const bar = read(LANDING, 'account.html');
54
- const arc = bar.match(/<path class="mr" d="([^"]+)"/)[1];
55
- assert.match(bar, /<circle class="mp" cx="100" cy="100" r="55"/);
56
- assert.match(bar, /<circle cx="156" cy="46" r="12" style="fill:var\(--accent\)"\/>/);
57
- const [ring, dot] = masksOf(SURFACES.apex.loader);
58
- assert.ok(ring.includes(`d='${arc}'`), 'the ring is the bar mark\'s arc');
59
- assert.ok(ring.includes("<circle cx='100' cy='100' r='55'/>"), 'the core is the bar mark\'s core');
60
- assert.ok(dot.includes("<circle cx='156' cy='46' r='12'/>"), 'the dot is the bar mark\'s dot');
55
+ assert.match(bar, /<svg class="bongosMark"[^>]*><use href="\/modules\/ui-design\/public\/brand\/mark\.svg#mark"\/><\/svg>/);
56
+ assert.deepEqual(masksOf(SURFACES.apex.loader), ['mark-body.svg', 'mark-dot.svg']);
61
57
  // The status page has no Bongos mark of its own: its loader carries the apex's two
62
58
  // masks byte for byte, so the two surfaces cannot drift into two logos.
63
59
  assert.deepEqual(masksOf(SURFACES.status.loader), masksOf(SURFACES.apex.loader));
@@ -91,9 +87,7 @@ for (const [name, { css, loader }] of Object.entries(SURFACES)) {
91
87
  for (const p of paints) assert.match(p, /^(var\(--[a-z-]+\)|color-mix\(in srgb, ?var\(--ink\) 30%, ?var\(--bg-card\)\))$/, `${p} is a token or a mix of one`);
92
88
  // The one accent is the dot: the live thing on a waiting page (the One Warm Thing Rule).
93
89
  assert.equal((css.match(/var\(--accent\)/g) || []).length, 1, 'the accent paints the dot alone');
94
- const masks = masksOf(loader);
95
- assert.equal(masks.length, 2, 'two masks: the ring and core, and the dot');
96
- for (const m of masks) assert.doesNotMatch(m.replace(/stroke='black'|fill='none'/g, ''), /fill='|stroke='|#/, 'a mask carries no colour of its own');
90
+ assert.deepEqual(masksOf(loader), ['mark-body.svg', 'mark-dot.svg'], 'two masks: the ring and core, and the dot');
97
91
  });
98
92
 
99
93
  test(`${name}: the dot shares the ring's grid cell, so no page padding can knock it off`, () => {
@@ -101,7 +101,8 @@ test('the hall-preview fixture carries every atom /me resolves', () => {
101
101
  // task 1005050: Accomplishments left it (folded into Profile; its hashes redirect);
102
102
  // task 1005051: Roadmap left it (folded into Goals; /roadmap redirects).
103
103
  // task 1005070: the remembered nav (the rail paints before /me).
104
- const SHELL_SHA = 'dbbe6f2eb49a65c3';
104
+ // task 1005088: the sidebar mark is drawn by reference to the one brand mark.
105
+ const SHELL_SHA = '2845bfedfaf7846f';
105
106
 
106
107
  test('shell.js has not changed without its cache-bust being bumped', () => {
107
108
  const actual = crypto.createHash('sha256').update(SHELL).digest('hex').slice(0, 16);
package/tests/raise.mjs CHANGED
@@ -157,7 +157,9 @@ test('a stranger gets the gate, never the copy', async () => {
157
157
  assert.doesNotMatch(html, /gamification of capitalism/);
158
158
  assert.equal(r.headers.get('x-robots-tag'), 'noindex, nofollow, noarchive');
159
159
  assert.equal((await get('/raise/media/x.mp4')).status, 401);
160
- assert.equal((await get('/raise/assets/logo-ink.svg')).status, 200, 'the gate needs its logo');
160
+ // the gate's logo is the shared one (task 1005088), served on every host, never a raise copy
161
+ assert.match(html, /src="\/modules\/ui-design\/public\/brand\/mark-light\.svg"/, 'the gate needs its logo');
162
+ assert.equal((await get('/raise/assets/logo-ink.svg')).status, 404, 'the old pasted copy is gone');
161
163
  assert.match(await (await get('/raise/nda')).text(), /CONFIDENTIALITY|Confidential/i);
162
164
  });
163
165
 
@@ -79,8 +79,11 @@ test('the banner is the logo, named from the branding pack, never a hardcoded wo
79
79
  assert.equal(W.bannerText, undefined, 'the "Working on the core of" banner is gone');
80
80
  const harbor = W.logoHtml({ identity: { worldName: 'Harbor', productName: 'Cloud Bongos' } });
81
81
  assert.match(harbor, /<svg class="wb__mark"/, 'no project logo: the Bongos mark');
82
- assert.match(harbor, /class="wb__ring"[^>]*pathLength="100"/, 'the ring can draw in');
83
- assert.match(harbor, /class="wb__moonlet"[^>]*fill="#fb9569"/, 'the salmon moon');
82
+ // the parts come from the one mark (task 1005088), whose ring carries pathLength="100"
83
+ assert.match(harbor, /<use class="wb__ring" href="\/modules\/ui-design\/public\/brand\/mark\.svg#mark-ring"\/>/, 'the ring can draw in');
84
+ assert.match(harbor, /<use class="wb__planet" href="[^"]*#mark-disc"\/>/, 'the planet');
85
+ assert.match(harbor, /<use class="wb__moonlet" href="[^"]*#mark-dot"\/>/, 'the moon');
86
+ assert.match(fs.readFileSync(path.join(ROOT, 'modules', 'ui-design', 'public', 'brand', 'mark.svg'), 'utf8'), /id="mark-ring"[^>]*pathLength="100"/);
84
87
  assert.match(harbor, /<span class="wb__name">Harbor<\/span>/);
85
88
  assert.match(W.logoHtml(undefined), /<span class="wb__name">this project<\/span>/, 'no branding: still a name');
86
89
  const own = W.logoHtml({ identity: { worldName: 'Harbor' }, theme: { logo: '/logo.png?a="b"' } });
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><style>.p{fill:#17181a}.r{stroke:#17181a}@media (prefers-color-scheme:dark){.p{fill:#e2e1e4}.r{stroke:#e2e1e4}}</style><path class="r" d="M137 31 A78 78 0 1 0 170 66" fill="none" stroke-width="24" stroke-linecap="round"/><circle class="p" cx="100" cy="100" r="50"/><circle cx="156" cy="46" r="18" fill="#fb9569"/></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" role="img" aria-label="Cloud Bongos"><path d="M137 31 A78 78 0 1 0 170 66" fill="none" stroke="#17181a" stroke-width="15" stroke-linecap="round"/><circle cx="100" cy="100" r="55" fill="#17181a"/><circle cx="156" cy="46" r="12" fill="#fb9569"/></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" role="img" aria-label="Cloud Bongos"><path d="M137 31 A78 78 0 1 0 170 66" fill="none" stroke="#e2e1e4" stroke-width="15" stroke-linecap="round"/><circle cx="100" cy="100" r="55" fill="#e2e1e4"/><circle cx="156" cy="46" r="12" fill="#fb9569"/></svg>