anentrypoint-design 0.0.240 → 0.0.242

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.240",
3
+ "version": "0.0.242",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -70,7 +70,7 @@ export function mountCommunityApp(root, adapter = {}) {
70
70
  for (const c of text) out.push(railPill(c, cur, false, s));
71
71
  } else if (!servers.length) {
72
72
  out.push(h('div', { class: 'group' }, 'rooms'));
73
- out.push(h('div', { class: 'rail-empty' }, 'no channels yet'));
73
+ out.push(h('div', { class: 'rail-empty', role: 'status' }, 'no rooms yet'));
74
74
  }
75
75
  if (voice.length) {
76
76
  out.push(h('div', { class: 'group' }, 'voice'));
@@ -102,7 +102,7 @@ export function ChannelCategory({ id, name, channels = [], collapsed, activeId,
102
102
  onclick: () => onToggle && onToggle(id),
103
103
  oncontextmenu: onContextMenu ? (e) => { e.preventDefault(); onContextMenu(id, e.clientX, e.clientY); } : null
104
104
  },
105
- h('svg', { class: 'cm-cat-arrow', viewBox: '0 0 24 24' }, h('path', { d: 'M7 10l5 5 5-5z' })),
105
+ h('span', { class: 'cm-cat-arrow' }, Icon('chevron-down')),
106
106
  h('span', { class: 'cm-cat-name' }, name),
107
107
  extraButton ? h('button', { class: 'cm-cat-extra', onclick: (e) => { e.stopPropagation(); extraButton.onClick && extraButton.onClick(id, e); }, 'aria-label': extraButton.title || 'Category action' }, extraButton.icon || extraButton.label || '+') : null,
108
108
  onAddChannel ? h('button', { class: 'cm-cat-add', onclick: (e) => { e.stopPropagation(); onAddChannel(id); }, 'aria-label': 'Add channel to ' + name }, '+') : null
@@ -157,7 +157,15 @@ export function UserPanel({ name, tag, color, muted, deafened, onMute, onDeafen,
157
157
  );
158
158
  }
159
159
 
160
- export function ChannelSidebar({ serverName, channels = [], categories = [], activeId, collapsedCats, onChannelClick, onCategoryToggle, onAddChannel, onChannelContext, userPanelProps } = {}) {
160
+ // Skeleton rows for a cold channel-list load reuses the kit-wide .ds-skel
161
+ // shimmer primitive (sessions.js / files.js) rather than a bare spinner.
162
+ function ChannelListSkeleton({ rows = 6 } = {}) {
163
+ return h('div', { class: 'cm-channel-list cm-channel-skeleton', 'aria-hidden': 'true' },
164
+ ...Array.from({ length: rows }, (_, i) => h('div', { key: 'csk' + i, class: 'cm-channel-item-skeleton' },
165
+ h('span', { class: 'ds-skel ds-skel-icon' }), h('span', { class: 'ds-skel ds-skel-title' }))));
166
+ }
167
+
168
+ export function ChannelSidebar({ serverName, channels = [], categories = [], activeId, collapsedCats, onChannelClick, onCategoryToggle, onAddChannel, onChannelContext, userPanelProps, loading = false } = {}) {
161
169
  const collapsed = collapsedCats || new Set();
162
170
  const uncategorized = channels.filter(c => !c.categoryId || !categories.find(cat => cat.id === c.categoryId));
163
171
  const sorted = [...categories].sort((a, b) => (a.position || 0) - (b.position || 0));
@@ -165,9 +173,11 @@ export function ChannelSidebar({ serverName, channels = [], categories = [], act
165
173
  h('div', { class: 'cm-server-header' },
166
174
  h('span', { class: 'cm-server-header-name' }, serverName || 'Server'),
167
175
  ),
168
- h('div', { class: 'cm-channel-list' },
176
+ loading ? ChannelListSkeleton() : h('div', { class: 'cm-channel-list' },
169
177
  (sorted.length === 0 && uncategorized.length === 0)
170
- ? h('div', { class: 'cm-channel-empty' }, 'no channels yet')
178
+ ? h('div', { class: 'cm-channel-empty', role: 'status' },
179
+ Icon('hash', { size: 20 }),
180
+ h('span', { class: 'cm-channel-empty-text' }, 'no channels yet — add one to get this server started'))
171
181
  : null,
172
182
  ...sorted.map(cat => ChannelCategory({
173
183
  id: cat.id,
@@ -204,11 +214,22 @@ export function MemberItem({ identity, name, color, status = 'online' } = {}) {
204
214
  );
205
215
  }
206
216
 
207
- export function MemberList({ categories = [], open } = {}) {
217
+ // Skeleton rows for a cold member-list load, matching FileSkeleton/session
218
+ // skeleton shape (icon + title placeholder), never a bare spinner.
219
+ function MemberListSkeleton({ rows = 6 } = {}) {
220
+ return h('div', { class: 'cm-member-list cm-member-skeleton open', 'aria-hidden': 'true' },
221
+ ...Array.from({ length: rows }, (_, i) => h('div', { key: 'msk' + i, class: 'cm-member-item-skeleton' },
222
+ h('span', { class: 'ds-skel ds-skel-icon' }), h('span', { class: 'ds-skel ds-skel-title' }))));
223
+ }
224
+
225
+ export function MemberList({ categories = [], open, loading = false } = {}) {
226
+ if (loading) return MemberListSkeleton();
208
227
  const total = categories.reduce((n, cat) => n + (cat.members ? cat.members.length : 0), 0);
209
228
  return h('div', { class: 'cm-member-list' + (open ? ' open' : '') },
210
229
  total === 0
211
- ? h('div', { key: '_empty', class: 'cm-member-empty' }, 'no members')
230
+ ? h('div', { key: '_empty', class: 'cm-member-empty', role: 'status' },
231
+ Icon('members', { size: 20 }),
232
+ h('span', { class: 'cm-member-empty-text' }, 'no members in this channel yet'))
212
233
  : null,
213
234
  ...categories.flatMap(cat => [
214
235
  h('div', { class: 'cm-member-category', key: cat.label }, `${cat.label} — ${cat.members.length}`),
@@ -310,7 +331,16 @@ function fmtRelTime(ts) {
310
331
  return Math.floor(hr / 24) + 'd';
311
332
  }
312
333
 
313
- export function ThreadPanel({ threads = [], activeId = null, title = 'Threads', onSelect, onCreate, onClose } = {}) {
334
+ // Skeleton rows for a cold thread/post-list load. Two lines per row (title +
335
+ // meta) mirrors cm-tp-item/cm-forum-item's actual shape so the shimmer
336
+ // doesn't jump on load. Reuses the kit-wide .ds-skel shimmer primitive.
337
+ function ListSkeleton({ cls, rows = 5 } = {}) {
338
+ return h('div', { class: cls + ' cm-list-skeleton', 'aria-hidden': 'true' },
339
+ ...Array.from({ length: rows }, (_, i) => h('div', { key: 'lsk' + i, class: 'cm-list-item-skeleton' },
340
+ h('span', { class: 'ds-skel ds-skel-title' }), h('span', { class: 'ds-skel ds-skel-meta' }))));
341
+ }
342
+
343
+ export function ThreadPanel({ threads = [], activeId = null, title = 'Threads', onSelect, onCreate, onClose, loading = false } = {}) {
314
344
  const list = Array.isArray(threads) ? threads : [];
315
345
  return h('div', { class: 'cm-thread-panel', role: 'complementary', 'aria-label': title },
316
346
  h('div', { class: 'cm-tp-head' },
@@ -320,7 +350,7 @@ export function ThreadPanel({ threads = [], activeId = null, title = 'Threads',
320
350
  onClose ? h('button', { type: 'button', class: 'cm-tp-close', 'aria-label': 'close', title: 'Close', onclick: onClose }, Icon('x')) : null
321
351
  )
322
352
  ),
323
- h('div', { class: 'cm-tp-list' },
353
+ loading ? ListSkeleton({ cls: 'cm-tp-list' }) : h('div', { class: 'cm-tp-list' },
324
354
  list.length
325
355
  ? list.map(t => h('button', {
326
356
  type: 'button', key: 'tp-' + t.id,
@@ -335,12 +365,14 @@ export function ThreadPanel({ threads = [], activeId = null, title = 'Threads',
335
365
  t.time ? h('span', { class: 'cm-tp-item-time' }, fmtRelTime(t.time)) : null
336
366
  )
337
367
  ))
338
- : h('div', { class: 'cm-tp-empty' }, 'No threads yet')
368
+ : h('div', { class: 'cm-tp-empty', role: 'status' },
369
+ Icon('thread', { size: 20 }),
370
+ h('span', { class: 'cm-tp-empty-text' }, onCreate ? 'no threads yet — start one' : 'no threads yet'))
339
371
  )
340
372
  );
341
373
  }
342
374
 
343
- export function ForumView({ posts = [], onSearch, onSort, onSelect, onNewPost } = {}) {
375
+ export function ForumView({ posts = [], onSearch, onSort, onSelect, onNewPost, loading = false } = {}) {
344
376
  const list = Array.isArray(posts) ? posts : [];
345
377
  return h('div', { class: 'cm-forum', role: 'region', 'aria-label': 'forum' },
346
378
  h('div', { class: 'cm-forum-toolbar' },
@@ -359,7 +391,7 @@ export function ForumView({ posts = [], onSearch, onSort, onSelect, onNewPost }
359
391
  ),
360
392
  onNewPost ? h('button', { type: 'button', class: 'cm-forum-new', onclick: onNewPost }, 'New post') : null
361
393
  ),
362
- h('div', { class: 'cm-forum-list' },
394
+ loading ? ListSkeleton({ cls: 'cm-forum-list' }) : h('div', { class: 'cm-forum-list' },
363
395
  list.length
364
396
  ? list.map(p => h('button', {
365
397
  type: 'button', key: 'fp-' + p.id, class: 'cm-forum-item',
@@ -379,7 +411,9 @@ export function ForumView({ posts = [], onSearch, onSort, onSelect, onNewPost }
379
411
  : null
380
412
  )
381
413
  ))
382
- : h('div', { class: 'cm-forum-empty' }, 'No posts yet')
414
+ : h('div', { class: 'cm-forum-empty', role: 'status' },
415
+ Icon('forum', { size: 20 }),
416
+ h('span', { class: 'cm-forum-empty-text' }, onNewPost ? 'no posts yet — start the discussion' : 'no posts yet'))
383
417
  )
384
418
  );
385
419
  }
@@ -128,7 +128,7 @@ export function Section({ title, eyebrow, children, id }) {
128
128
  );
129
129
  }
130
130
 
131
- export function Hero({ eyebrow, title, body, accent, badge, badgeCount, actions }) {
131
+ export function Hero({ eyebrow, title, body, accent, actions }) {
132
132
  // Eyebrow + title share the title grid-area so the named-area layout stays
133
133
  // intact; body and actions occupy the offset lower columns.
134
134
  return h('div', { class: 'ds-hero' },
@@ -140,8 +140,7 @@ export function Hero({ eyebrow, title, body, accent, badge, badgeCount, actions
140
140
  body,
141
141
  accent ? h('span', { class: 'ds-hero-accent' }, ' ' + accent) : null
142
142
  ) : null,
143
- actions ? h('div', { class: 'ds-hero-actions' }, ...(Array.isArray(actions) ? actions : [actions])) : null,
144
- badge ? h('div', { class: 'ds-hero-badge' }, Panel({ title: badge, count: badgeCount, kind: 'inline', children: [] })) : null
143
+ actions ? h('div', { class: 'ds-hero-actions' }, ...(Array.isArray(actions) ? actions : [actions])) : null
145
144
  );
146
145
  }
147
146
 
@@ -169,7 +168,8 @@ export function Install({ cmd, copied, onCopy }) {
169
168
  );
170
169
  }
171
170
 
172
- export function Receipt({ rows = [] }) {
171
+ export function Receipt({ rows = [], emptyText = 'nothing here yet' }) {
172
+ if (!rows.length) return h('div', { class: 'empty' }, emptyText);
173
173
  return h('table', { class: 'kv' },
174
174
  h('tbody', {}, ...rows.map(([k, v], i) =>
175
175
  h('tr', { key: i }, h('td', {}, k), h('td', {}, v))
@@ -177,7 +177,8 @@ export function Receipt({ rows = [] }) {
177
177
  );
178
178
  }
179
179
 
180
- export function Changelog({ entries = [] }) {
180
+ export function Changelog({ entries = [], emptyText = 'no changelog entries yet' }) {
181
+ if (!entries.length) return h('div', { class: 'empty' }, emptyText);
181
182
  return Panel({
182
183
  kind: 'wide',
183
184
  children: entries.map((e, i) =>
@@ -242,7 +243,8 @@ export function Manifesto({ paragraphs = [], maxWidth }) {
242
243
  );
243
244
  }
244
245
 
245
- export function Kpi({ items = [] }) {
246
+ export function Kpi({ items = [], emptyText = 'no metrics yet' }) {
247
+ if (!items.length) return h('div', { class: 'empty' }, emptyText);
246
248
  return h('div', { class: 'kpi' }, ...items.map(([n, l], i) =>
247
249
  h('div', { key: i, class: 'kpi-card' },
248
250
  h('div', { class: 'num' }, String(n)),
@@ -87,7 +87,7 @@ export function Glyph({ children, color, size = 'base', label } = {}) {
87
87
 
88
88
  // Monochrome inline-SVG icons (stroke=currentColor) so chrome reads as one
89
89
  // coherent line-icon set instead of multicolor OS emoji. 16px box, 1.6 stroke.
90
- const ICON_PATHS = {
90
+ export const ICON_PATHS = {
91
91
  mic: '<path d="M12 3a3 3 0 0 0-3 3v5a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3z"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/>',
92
92
  'mic-off': '<path d="M9 9v2a3 3 0 0 0 4.5 2.6M15 11V6a3 3 0 0 0-5.9-.8"/><path d="M5 11a7 7 0 0 0 11.5 5.4M12 18v3"/><path d="m4 4 16 16"/>',
93
93
  speaker: '<path d="M11 5 6 9H3v6h3l5 4z"/><path d="M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13"/>',
@@ -8,7 +8,7 @@
8
8
  standalone theme.css resolves cleanly. */
9
9
 
10
10
  .app-fd .fd-pre {
11
- font-family: var(--os-mono, JetBrains Mono, monospace);
11
+ font-family: var(--os-mono, monospace);
12
12
  font-size: var(--fs-tiny, 12px);
13
13
  white-space: pre-wrap;
14
14
  word-break: break-all;
@@ -29,7 +29,7 @@
29
29
  .fd-chat-row { display: flex; gap: var(--space-3, 16px); flex-wrap: wrap; }
30
30
  .fd-chat-field { display: flex; flex-direction: column; gap: var(--space-1, 4px); min-width: 120px; }
31
31
  .fd-chat-field-grow { flex: 2; min-width: 140px; }
32
- .fd-chat-field > label { font-family: var(--os-mono, JetBrains Mono, monospace); font-size: var(--fs-micro, 11px); color: var(--os-fg-3); letter-spacing: var(--tr-label, 0.10em); text-transform: uppercase; }
32
+ .fd-chat-field > label { font-family: var(--os-mono, monospace); font-size: var(--fs-micro, 11px); color: var(--os-fg-3); letter-spacing: var(--tr-label, 0.10em); text-transform: uppercase; }
33
33
  .fd-chat-field > input { width: 100%; box-sizing: border-box; }
34
34
  .fd-chat-submit { display: flex; gap: var(--space-3, 16px); align-items: flex-end; }
35
35
  .fd-chat-submit textarea { flex: 1; resize: none; min-height: 80px; }
@@ -44,7 +44,7 @@
44
44
  }
45
45
  .fd-chatlog-msg { padding: var(--space-1, 4px) var(--space-3, 16px); background: var(--os-bg-2); white-space: pre-wrap; word-break: break-word; }
46
46
  .fd-chatlog-assistant { color: var(--os-accent); }
47
- .fd-chatlog-tool { margin: var(--space-1, 4px) 0; padding: var(--space-1, 4px) var(--space-2, 8px); background: var(--os-bg-3); border-radius: var(--os-radius-sm, 6px); font-family: var(--os-mono, JetBrains Mono, monospace); font-size: var(--fs-tiny, 12px); }
47
+ .fd-chatlog-tool { margin: var(--space-1, 4px) 0; padding: var(--space-1, 4px) var(--space-2, 8px); background: var(--os-bg-3); border-radius: var(--os-radius-sm, 6px); font-family: var(--os-mono, monospace); font-size: var(--fs-tiny, 12px); }
48
48
  .fd-chatlog-tool-sum { cursor: pointer; color: var(--os-red); padding: var(--space-1, 4px) 0; }
49
49
  .fd-chatlog-tool-body { margin: var(--space-1, 4px) 0 0; white-space: pre-wrap; word-break: break-all; max-height: 200px; overflow-y: auto; }
50
50
 
@@ -59,7 +59,7 @@
59
59
  .fd-chat-config .fd-chat-field { display: flex; flex-direction: column; gap: var(--space-1, 4px); min-width: 120px; }
60
60
  .fd-chat-config .fd-chat-field > label { font-family: var(--os-mono, monospace); font-size: 10px; opacity: 0.6; letter-spacing: 0.05em; text-transform: uppercase; }
61
61
  .fd-chat-config .fd-chat-field > input,
62
- .fd-chat-config .fd-chat-field > select { width: 100%; box-sizing: border-box; padding: 6px 8px; background: var(--panel-1, transparent); color: var(--fg, inherit); border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent); border-radius: 6px; font: inherit; font-size: 12px; }
62
+ .fd-chat-config .fd-chat-field > select { width: 100%; box-sizing: border-box; padding: 6px 8px; background: var(--panel-1, transparent); color: var(--fg, inherit); border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent); border-radius: var(--r-0); font: inherit; font-size: 12px; }
63
63
  .fd-chat-config .fd-chat-field > input:focus-visible,
64
64
  .fd-chat-config .fd-chat-field > select:focus-visible { outline: 2px solid var(--os-accent, #247420); outline-offset: 0; border-color: color-mix(in oklab, var(--os-accent, #247420) 60%, transparent); }
65
65
  .fd-chat-config .fd-chat-row { display: flex; gap: var(--space-2, 8px); flex-wrap: wrap; }
@@ -68,5 +68,5 @@
68
68
  .app-fd ds-chat.fd-dashboard-chat { flex: 1 1 auto; min-height: 280px; display: flex; flex-direction: column; overflow: hidden; }
69
69
 
70
70
  .fd-chat-actions { display: inline-flex; gap: var(--space-1, 4px); align-items: center; }
71
- .fd-chat-actions .btn-secondary { background: transparent; color: var(--danger, #c0392b); border: 1px solid color-mix(in oklab, var(--danger, #c0392b) 40%, transparent); cursor: pointer; padding: 2px 8px; border-radius: 4px; font: inherit; font-size: 12px; }
71
+ .fd-chat-actions .btn-secondary { background: transparent; color: var(--danger, #c0392b); border: 1px solid color-mix(in oklab, var(--danger, #c0392b) 40%, transparent); cursor: pointer; padding: 2px 8px; border-radius: var(--r-0); font: inherit; font-size: 12px; }
72
72
  .fd-chat-actions .btn-secondary:hover { background: color-mix(in oklab, var(--danger, #c0392b) 10%, transparent); }
@@ -1,17 +1,39 @@
1
- export const icons = {
2
- terminal: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/></svg>',
3
- browser: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 010 18M12 3a14 14 0 000 18"/></svg>',
4
- canvas: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="14" rx="2"/><path d="M3 17l6-5 4 3 5-4 3 2"/></svg>',
5
- files: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6a2 2 0 012-2h4l2 2h8a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2z"/></svg>',
6
- monitor: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12l4-8 4 14 4-10 4 8 2-3"/></svg>',
7
- validator: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l4 4L19 6"/></svg>',
8
- about: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v.01M11 12h1v5h1"/></svg>',
9
- apps: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></svg>',
10
- plus: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>',
11
- home: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16M4 12h16M4 18h16"/></svg>',
12
- xdisplay: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="13" rx="1.5"/><path d="M8 21h8M12 17v4M9 9l6 4M15 9l-6 4"/></svg>',
13
- close: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M18 6l-12 12"/></svg>',
14
- chat: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5h16v11H8l-4 4z"/><path d="M8 9h8M8 12h6"/></svg>',
15
- tools: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 7l3-3 3 3-3 3-3-3zM7 14l3 3-7 7-3-3 7-7zM5 7l3-3M14 14l6 6"/></svg>',
16
- freddie: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2M8 12a4 4 0 008 0"/></svg>',
1
+ import { ICON_PATHS } from '../../components/shell.js';
2
+
3
+ // os-window-manager app icons. Concepts here (terminal/browser/canvas/monitor/
4
+ // apps/xdisplay/tools/freddie) are OS-app glyphs with no equivalent in the
5
+ // shared ICON_PATHS UI-icon set, so they keep their own path data but every
6
+ // entry renders through iconMarkup()'s attribute contract (viewBox 0 0 24 24,
7
+ // stroke=currentColor, shared --ds-icon-stroke var) instead of a second
8
+ // hardcoded stroke-width, so this module can't drift from the system's
9
+ // visual weight. Where a concept already exists in ICON_PATHS (close/files/
10
+ // validator/about/apps/home/chat), reuse that entry's path data directly.
11
+ const OS_PATHS = {
12
+ terminal: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9l3 3-3 3M13 15h4"/>',
13
+ browser: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 010 18M12 3a14 14 0 000 18"/>',
14
+ canvas: '<rect x="3" y="3" width="18" height="14" rx="2"/><path d="M3 17l6-5 4 3 5-4 3 2"/>',
15
+ files: ICON_PATHS.folder,
16
+ monitor: '<path d="M3 12l4-8 4 14 4-10 4 8 2-3"/>',
17
+ validator: ICON_PATHS.check,
18
+ about: ICON_PATHS.info,
19
+ apps: ICON_PATHS.grid,
20
+ plus: '<path d="M12 5v14M5 12h14"/>',
21
+ home: ICON_PATHS.menu,
22
+ xdisplay: '<rect x="3" y="4" width="18" height="13" rx="1.5"/><path d="M8 21h8M12 17v4M9 9l6 4M15 9l-6 4"/>',
23
+ close: ICON_PATHS.x,
24
+ chat: ICON_PATHS.forum,
25
+ tools: '<path d="M14 7l3-3 3 3-3 3-3-3zM7 14l3 3-7 7-3-3 7-7zM5 7l3-3M14 14l6 6"/>',
26
+ freddie: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2M8 12a4 4 0 008 0"/>',
17
27
  };
28
+
29
+ // iconMarkup() only resolves names already registered in the shared
30
+ // ICON_PATHS table; this module's names are private to the os kit, so each
31
+ // entry is rendered against the identical attr contract iconMarkup() uses
32
+ // (viewBox/stroke/linecap/--ds-icon-stroke) rather than forking a second
33
+ // stroke-width constant.
34
+ export const icons = Object.fromEntries(
35
+ Object.entries(OS_PATHS).map(([name, inner]) => [
36
+ name,
37
+ `<svg class="ds-icon ds-icon-${name}" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="var(--ds-icon-stroke, 1.6)" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${inner}</svg>`
38
+ ])
39
+ );
@@ -104,7 +104,7 @@ html, body {
104
104
  font: inherit;
105
105
  font-family: var(--os-font);
106
106
  font-size: 13px;
107
- border-radius: 999px;
107
+ border-radius: var(--r-pill, 999px);
108
108
  transition: background 80ms ease, color 80ms ease;
109
109
  display: inline-flex;
110
110
  align-items: center;
@@ -173,7 +173,7 @@ html, body {
173
173
  border: none;
174
174
  background: var(--os-bg-1);
175
175
  color: var(--os-fg-2);
176
- border-radius: 999px;
176
+ border-radius: var(--r-pill, 999px);
177
177
  padding: 6px 14px;
178
178
  font-size: 12px;
179
179
  font-family: var(--os-font);
@@ -575,7 +575,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
575
575
  z-index: 9050;
576
576
  background: color-mix(in oklab, var(--os-accent) 20%, transparent);
577
577
  border: 2px solid var(--os-accent);
578
- border-radius: 8px;
578
+ border-radius: var(--r-0);
579
579
  /* Animate only geometry, never `all` — `transition: all` animated display/
580
580
  * opacity too, producing a one-frame ghost on show (jank-pass fix). */
581
581
  transition: left 80ms ease, top 80ms ease, width 80ms ease, height 80ms ease;
@@ -593,7 +593,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
593
593
  padding: 16px 20px;
594
594
  background: var(--os-bg-2);
595
595
  border: 1px solid var(--os-accent);
596
- border-radius: 8px;
596
+ border-radius: var(--r-0);
597
597
  z-index: 9600;
598
598
  font-family: var(--ff-ui);
599
599
  color: var(--os-fg);
@@ -602,7 +602,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
602
602
  }
603
603
  .ds-247420 .wm-switcher-item {
604
604
  padding: 8px 12px;
605
- border-radius: 4px;
605
+ border-radius: var(--r-0);
606
606
  display: flex;
607
607
  align-items: center;
608
608
  gap: 10px;
@@ -621,10 +621,10 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
621
621
  }
622
622
  .ds-247420 freddie-chat .chat-bubble pre,
623
623
  .ds-247420 freddie-chat .chat-bubble code {
624
- font-family: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;
624
+ font-family: var(--ff-mono, ui-monospace, Menlo, Consolas, monospace);
625
625
  }
626
626
  .ds-247420 freddie-chat .chat-head {
627
- font-family: var(--ff-display, 'Inter', system-ui, sans-serif);
627
+ font-family: var(--ff-display, system-ui, sans-serif);
628
628
  font-weight: 700;
629
629
  }
630
630
 
@@ -664,7 +664,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
664
664
  .ds-247420 .tb-sess-badge {
665
665
  display: inline-flex; align-items: center; justify-content: center;
666
666
  min-width: 16px; height: 14px; padding: 0 4px;
667
- border-radius: 7px;
667
+ border-radius: var(--r-0);
668
668
  background: color-mix(in oklab, var(--fg) 14%, transparent);
669
669
  font-size: 9px; font-weight: 600; line-height: 1;
670
670
  }
@@ -708,7 +708,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
708
708
  .tb-sess-modal {
709
709
  background: var(--bg);
710
710
  color: var(--fg);
711
- border-radius: 12px;
711
+ border-radius: var(--r-1);
712
712
  box-shadow: var(--shadow-overlay);
713
713
  min-width: 320px; max-width: 480px;
714
714
  border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
@@ -724,7 +724,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
724
724
  width: 100%; box-sizing: border-box;
725
725
  height: 32px; padding: 0 10px;
726
726
  border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
727
- border-radius: 6px;
727
+ border-radius: var(--r-0);
728
728
  background: color-mix(in oklab, var(--fg) 6%, var(--bg));
729
729
  color: inherit;
730
730
  font-family: inherit; font-size: 13px;
@@ -735,7 +735,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
735
735
  .tb-sess-modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
736
736
  .tb-sess-modal-btn {
737
737
  height: 28px; padding: 0 14px;
738
- border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
738
+ border-radius: var(--r-0); border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
739
739
  background: transparent; color: inherit;
740
740
  font-family: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
741
741
  transition: background 120ms ease, border-color 120ms ease;
@@ -756,7 +756,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
756
756
  background: var(--bg);
757
757
  color: var(--fg);
758
758
  border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent);
759
- border-radius: 16px;
759
+ border-radius: var(--r-2);
760
760
  box-shadow: var(--shadow-3);
761
761
  padding: 32px 40px; text-align: center;
762
762
  font-family: var(--ff-ui);
@@ -767,7 +767,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
767
767
  .tb-sess-empty-cta {
768
768
  height: 40px; padding: 0 24px;
769
769
  background: var(--os-accent); color: var(--on-color);
770
- border: 0; border-radius: 999px;
770
+ border: 0; border-radius: var(--r-pill, 999px);
771
771
  font-family: inherit; font-size: 14px; font-weight: 600;
772
772
  cursor: pointer;
773
773
  transition: transform 120ms ease, box-shadow 120ms ease;
@@ -780,23 +780,23 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
780
780
  .ds-247420 .tb-sessions-title { font-weight: 600; font-size: 14px; }
781
781
  .ds-247420 .tb-sessions-count { font-size: 12px; opacity: 0.6; margin-left: 4px; }
782
782
  .ds-247420 .tb-sessions-spacer { flex: 1; }
783
- .ds-247420 .tb-sessions-btn { height: 28px; padding: 0 12px; border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent); background: transparent; color: inherit; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit; }
783
+ .ds-247420 .tb-sessions-btn { height: 28px; padding: 0 12px; border-radius: var(--r-0); border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent); background: transparent; color: inherit; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit; }
784
784
  .ds-247420 .tb-sessions-btn:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
785
785
  .ds-247420 .tb-sessions-btn.primary { background: var(--os-accent); color: var(--on-color); border-color: var(--os-accent); }
786
786
  .ds-247420 .tb-sessions-btn.danger { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
787
787
  .ds-247420 .tb-sessions-btn:disabled { opacity: 0.4; cursor: not-allowed; }
788
788
  .ds-247420 .tb-sessions-grid { flex: 1; overflow: auto; padding: 14px; display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; align-content: start; }
789
- .ds-247420 .tb-sessions-card { padding: 12px; border-radius: 10px; border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent); background: color-mix(in oklab, var(--fg) 3%, transparent); display: flex; flex-direction: column; gap: 8px; transition: border-color 120ms ease, transform 120ms ease; }
789
+ .ds-247420 .tb-sessions-card { padding: 12px; border-radius: var(--r-1, 10px); border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent); background: color-mix(in oklab, var(--fg) 3%, transparent); display: flex; flex-direction: column; gap: 8px; transition: border-color 120ms ease, transform 120ms ease; }
790
790
  .ds-247420 .tb-sessions-card:hover { border-color: var(--os-accent); }
791
791
  .ds-247420 .tb-sessions-card.active { border-color: var(--os-accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent) 30%, transparent); }
792
792
  .ds-247420 .tb-sessions-card-head { display: flex; align-items: center; gap: 8px; }
793
793
  .ds-247420 .tb-sessions-card-check { width: 14px; height: 14px; cursor: pointer; flex: 0 0 14px; }
794
- .ds-247420 .tb-sessions-card-name { font-weight: 600; font-size: 13px; flex: 1; outline: none; padding: 2px 4px; border-radius: 4px; }
794
+ .ds-247420 .tb-sessions-card-name { font-weight: 600; font-size: 13px; flex: 1; outline: none; padding: 2px 4px; border-radius: var(--r-0); }
795
795
  .ds-247420 .tb-sessions-card-name[contenteditable="true"] { background: color-mix(in oklab, var(--fg) 8%, transparent); }
796
796
  .ds-247420 .tb-sessions-card-id { font-family: var(--os-mono, monospace); font-size: 10px; opacity: 0.5; }
797
797
  .ds-247420 .tb-sessions-card-stats { font-size: 11px; opacity: 0.7; display: flex; gap: 12px; }
798
798
  .ds-247420 .tb-sessions-card-actions { display: flex; gap: 6px; margin-top: 4px; }
799
- .ds-247420 .tb-sessions-card-actions button { flex: 1; height: 24px; font-size: 11px; padding: 0 8px; border-radius: 4px; border: 1px solid color-mix(in oklab, var(--fg) 16%, transparent); background: transparent; color: inherit; cursor: pointer; font-family: inherit; }
799
+ .ds-247420 .tb-sessions-card-actions button { flex: 1; height: 24px; font-size: 11px; padding: 0 8px; border-radius: var(--r-0); border: 1px solid color-mix(in oklab, var(--fg) 16%, transparent); background: transparent; color: inherit; cursor: pointer; font-family: inherit; }
800
800
  .ds-247420 .tb-sessions-card-actions button:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
801
801
  .ds-247420 .tb-sessions-card-actions button.danger:hover { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
802
802
  .ds-247420 .tb-sessions-empty-mid { padding: 40px; text-align: center; opacity: 0.6; font-size: 13px; }
@@ -846,7 +846,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
846
846
  .ds-247420 .cc-field { display: flex; flex-direction: column; gap: .2em; }
847
847
  .ds-247420 .cc-field-label { font-size: 11px; opacity: .65; text-transform: lowercase; }
848
848
  .ds-247420 .cc-strip select,
849
- .ds-247420 .cc-strip input { font: inherit; font-size: 12px; padding: .3em .4em; width: 100%; box-sizing: border-box; background: var(--panel-1, transparent); color: var(--fg, inherit); border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 6px; }
849
+ .ds-247420 .cc-strip input { font: inherit; font-size: 12px; padding: .3em .4em; width: 100%; box-sizing: border-box; background: var(--panel-1, transparent); color: var(--fg, inherit); border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-0); }
850
850
  .ds-247420 .cc-acp-mode-wrap { display: flex; align-items: center; gap: .4em; }
851
851
  .ds-247420 .cc-acp-mode-wrap select { flex: 1; }
852
852
  .ds-247420 .cc-acp-status { opacity: .5; font-size: 13px; }
@@ -865,7 +865,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
865
865
  .ds-247420 .fsb-crumb { cursor: pointer; opacity: .75; text-decoration: none; color: inherit; }
866
866
  .ds-247420 .fsb-crumb:hover { opacity: 1; text-decoration: underline; }
867
867
  .ds-247420 .fsb-crumb-sep { opacity: .4; }
868
- .ds-247420 .fsb-btn { all: unset; cursor: pointer; padding: .3em .55em; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 6px; opacity: .85; }
868
+ .ds-247420 .fsb-btn { all: unset; cursor: pointer; padding: .3em .55em; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-0); opacity: .85; }
869
869
  .ds-247420 .fsb-btn:hover { opacity: 1; background: color-mix(in oklab, var(--fg) 6%, transparent); }
870
870
  .ds-247420 .fsb-list { flex: 1; min-height: 0; overflow: auto; padding: .3em 0; }
871
871
  .ds-247420 .fsb-row { display: flex; align-items: center; gap: .6em; padding: .35em .7em; cursor: pointer; border: 0; }
@@ -880,7 +880,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
880
880
  .ds-247420 .fsb-row:hover .fsb-actions,
881
881
  .ds-247420 .fsb-row:focus-within .fsb-actions { opacity: 1; }
882
882
  @media (hover: none) { .ds-247420 .fsb-actions { opacity: 1; } }
883
- .ds-247420 .fsb-act { all: unset; cursor: pointer; padding: .1em .35em; border-radius: 5px; opacity: .7; font-size: 12px; }
883
+ .ds-247420 .fsb-act { all: unset; cursor: pointer; padding: .1em .35em; border-radius: var(--r-0); opacity: .7; font-size: 12px; }
884
884
  .ds-247420 .fsb-act:hover { opacity: 1; background: color-mix(in oklab, var(--fg) 12%, transparent); }
885
885
  .ds-247420 .fsb-empty { opacity: .5; padding: 1.5em; text-align: center; font-style: italic; }
886
886
  .ds-247420 .fsb-view { flex: 1; min-height: 0; overflow: auto; margin: 0; padding: .7em; white-space: pre-wrap; word-break: break-word; font: 12px/1.5 var(--os-mono, ui-monospace, monospace); background: var(--panel-1, transparent); }
@@ -893,16 +893,16 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
893
893
  .ds-247420 .wm-canvas { position: absolute; inset: 0; transform-origin: 0 0; will-change: transform; }
894
894
 
895
895
  /* ---- wm context menu (was: docs/wm.js showWindowMenu cssText) ---- */
896
- .ds-247420 .wm-context-menu { position: fixed; background: var(--panel-2, #1a1a1a); border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 6px; z-index: 9700; font-family: var(--ff-ui); color: var(--fg, #fff); min-width: 140px; box-shadow: 0 8px 32px rgba(0, 0, 0, .35); padding: 4px; }
897
- .ds-247420 .wm-context-menu-item { display: block; width: 100%; padding: 7px 10px; border: none; border-radius: 4px; background: none; color: inherit; font-family: inherit; text-align: left; cursor: pointer; font-size: 13px; }
896
+ .ds-247420 .wm-context-menu { position: fixed; background: var(--panel-2, #1a1a1a); border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-0); z-index: 9700; font-family: var(--ff-ui); color: var(--fg, #fff); min-width: 140px; box-shadow: 0 8px 32px rgba(0, 0, 0, .35); padding: 4px; }
897
+ .ds-247420 .wm-context-menu-item { display: block; width: 100%; padding: 7px 10px; border: none; border-radius: var(--r-0); background: none; color: inherit; font-family: inherit; text-align: left; cursor: pointer; font-size: 13px; }
898
898
  .ds-247420 .wm-context-menu-item:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); }
899
899
 
900
900
  /* ---- todo app (was: docs/apps.js todo-app cssText) ---- */
901
901
  .ds-247420 .tb-todo-bar { display: flex; gap: 6px; margin-bottom: 8px; }
902
- .ds-247420 .tb-todo-input { flex: 1; padding: 5px 8px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 4px; font: inherit; background: var(--panel-1, transparent); color: var(--fg, inherit); }
902
+ .ds-247420 .tb-todo-input { flex: 1; padding: 5px 8px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-0); font: inherit; background: var(--panel-1, transparent); color: var(--fg, inherit); }
903
903
  .ds-247420 .tb-todo-list { list-style: none; padding: 0; margin: 6px 0; }
904
904
  .ds-247420 .tb-todo-footer { display: flex; gap: 8px; align-items: center; margin-top: 6px; font-size: 11px; }
905
- .ds-247420 .tb-todo-status { margin-top: 10px; font-size: 11px; color: color-mix(in oklab, var(--fg) 55%, transparent); padding: 6px 8px; background: var(--panel-1, transparent); border-radius: 4px; min-height: 14px; }
905
+ .ds-247420 .tb-todo-status { margin-top: 10px; font-size: 11px; color: color-mix(in oklab, var(--fg) 55%, transparent); padding: 6px 8px; background: var(--panel-1, transparent); border-radius: var(--r-0); min-height: 14px; }
906
906
  .ds-247420 .tb-todo-item { display: flex; gap: 8px; align-items: center; padding: 5px 6px; border-bottom: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
907
907
  .ds-247420 .tb-todo-text { flex: 1; }
908
908
  .ds-247420 .tb-todo-text.is-done { text-decoration: line-through; color: color-mix(in oklab, var(--fg) 45%, transparent); }
@@ -916,7 +916,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
916
916
  .ds-247420 .fk-title { font-weight: 600; margin-bottom: 8px; }
917
917
  .ds-247420 .fk-nim-wrap { display: flex; gap: 6px; align-items: center; margin: 4px 0 10px 0; }
918
918
  .ds-247420 .fk-nim-in { font-family: var(--os-mono, monospace); font-size: 11px; padding: 2px 4px; flex: 1; }
919
- .ds-247420 .fk-badge { font-size: 10px; padding: 2px 6px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 3px; color: var(--os-accent, #247420); }
919
+ .ds-247420 .fk-badge { font-size: 10px; padding: 2px 6px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-hair); color: var(--os-accent, #247420); }
920
920
  .ds-247420 .fk-agent-title,
921
921
  .ds-247420 .fk-host-title { margin-top: 14px; font-size: 11px; color: color-mix(in oklab, var(--fg) 60%, transparent); }
922
922
  .ds-247420 .fk-summary { font-size: 10px; color: color-mix(in oklab, var(--fg) 60%, transparent); margin: 6px 0; }
@@ -935,7 +935,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
935
935
  .ds-247420 .chat-msg.system .chat-bubble { background: transparent; border: 0; font-style: italic; opacity: 0.65; font-size: 12px; padding: 4px 8px; text-align: center; max-width: 100%; }
936
936
 
937
937
  /* Tool-call card — collapsible details with status icon + name + label. */
938
- .ds-247420 .chat-tool { display: block; background: var(--panel-1, color-mix(in oklab, var(--fg) 4%, transparent)); border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent); border-radius: 8px; padding: 0; max-width: min(640px, 92%); overflow: hidden; font-size: 12px; }
938
+ .ds-247420 .chat-tool { display: block; background: var(--panel-1, color-mix(in oklab, var(--fg) 4%, transparent)); border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent); border-radius: var(--r-0); padding: 0; max-width: min(640px, 92%); overflow: hidden; font-size: 12px; }
939
939
  .ds-247420 .chat-tool[open] { background: var(--panel-1, color-mix(in oklab, var(--fg) 6%, transparent)); }
940
940
  .ds-247420 .chat-tool.tool-error { border-color: color-mix(in oklab, var(--danger, #c0392b) 60%, transparent); }
941
941
  .ds-247420 .chat-tool.tool-done { border-color: color-mix(in oklab, var(--os-accent, #247420) 35%, transparent); }
@@ -952,7 +952,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
952
952
  .ds-247420 .chat-tool-body { padding: 4px 10px 10px; display: flex; flex-direction: column; gap: 8px; border-top: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
953
953
  .ds-247420 .chat-tool-section { display: flex; flex-direction: column; gap: 3px; }
954
954
  .ds-247420 .chat-tool-section-label { font-size: 10px; opacity: 0.5; text-transform: lowercase; letter-spacing: 0.05em; }
955
- .ds-247420 .chat-tool-pre { margin: 0; padding: 6px 8px; background: color-mix(in oklab, var(--fg) 4%, transparent); border-radius: 4px; max-height: 200px; overflow: auto; font: 11px/1.45 var(--os-mono, ui-monospace, monospace); white-space: pre-wrap; word-break: break-word; }
955
+ .ds-247420 .chat-tool-pre { margin: 0; padding: 6px 8px; background: color-mix(in oklab, var(--fg) 4%, transparent); border-radius: var(--r-0); max-height: 200px; overflow: auto; font: 11px/1.45 var(--os-mono, ui-monospace, monospace); white-space: pre-wrap; word-break: break-word; }
956
956
  .ds-247420 .chat-tool-pre.is-error { color: var(--danger, #c0392b); }
957
957
 
958
958
  /* Thinking indicator — typing dots + label, transient (assistant-side). */
@@ -969,7 +969,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
969
969
 
970
970
  /* Empty-state suggestion chips — clickable prompts. */
971
971
  .ds-247420 .chat-empty-suggestions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 12px; max-width: 480px; }
972
- .ds-247420 .chat-empty-suggestion { all: unset; cursor: pointer; font-size: 12px; padding: 6px 10px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: 999px; background: var(--panel-1, transparent); transition: background 120ms ease, border-color 120ms ease; }
972
+ .ds-247420 .chat-empty-suggestion { all: unset; cursor: pointer; font-size: 12px; padding: 6px 10px; border: 1px solid color-mix(in oklab, var(--fg) 18%, transparent); border-radius: var(--r-pill, 999px); background: var(--panel-1, transparent); transition: background 120ms ease, border-color 120ms ease; }
973
973
  .ds-247420 .chat-empty-suggestion:hover { background: color-mix(in oklab, var(--os-accent, #247420) 10%, transparent); border-color: var(--os-accent, #247420); }
974
974
  .ds-247420 .chat-empty-suggestion:focus-visible { outline: 2px solid var(--os-accent, #247420); outline-offset: 2px; }
975
975
 
@@ -1103,7 +1103,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1103
1103
  .ds-247420 .chat-thread::-webkit-scrollbar-track { background: transparent; }
1104
1104
  .ds-247420 .chat-thread::-webkit-scrollbar-thumb {
1105
1105
  background: color-mix(in oklab, var(--fg) 18%, transparent);
1106
- border-radius: 4px;
1106
+ border-radius: var(--r-0);
1107
1107
  }
1108
1108
  .ds-247420 .chat-thread::-webkit-scrollbar-thumb:hover {
1109
1109
  background: color-mix(in oklab, var(--fg) 30%, transparent);
@@ -1161,7 +1161,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1161
1161
  background: var(--panel-1, color-mix(in oklab, var(--fg) 5%, transparent));
1162
1162
  color: var(--fg);
1163
1163
  border: 1px solid color-mix(in oklab, var(--fg) 8%, transparent);
1164
- border-radius: 12px;
1164
+ border-radius: var(--r-1);
1165
1165
  padding: 8px 12px;
1166
1166
  font-size: 14px;
1167
1167
  line-height: 1.5;
@@ -1185,7 +1185,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1185
1185
  margin: 6px 0 0;
1186
1186
  padding: 8px 10px;
1187
1187
  background: color-mix(in oklab, var(--fg) 6%, transparent);
1188
- border-radius: 6px;
1188
+ border-radius: var(--r-0);
1189
1189
  max-height: 320px;
1190
1190
  overflow: auto;
1191
1191
  white-space: pre;
@@ -1252,7 +1252,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1252
1252
  background: var(--panel-1, color-mix(in oklab, var(--fg) 5%, transparent));
1253
1253
  color: var(--fg);
1254
1254
  border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent);
1255
- border-radius: 8px;
1255
+ border-radius: var(--r-0);
1256
1256
  padding: 8px 10px;
1257
1257
  resize: none;
1258
1258
  outline: none;
@@ -1283,7 +1283,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1283
1283
  justify-content: center;
1284
1284
  width: 32px;
1285
1285
  height: 32px;
1286
- border-radius: 6px;
1286
+ border-radius: var(--r-0);
1287
1287
  color: var(--fg);
1288
1288
  opacity: 0.65;
1289
1289
  transition: background-color 120ms ease, opacity 120ms ease;
@@ -1303,7 +1303,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1303
1303
  margin-left: auto;
1304
1304
  width: 36px;
1305
1305
  height: 32px;
1306
- border-radius: 6px;
1306
+ border-radius: var(--r-0);
1307
1307
  background: var(--os-accent, #247420);
1308
1308
  color: var(--on-color, #fff);
1309
1309
  display: inline-flex;
@@ -1349,7 +1349,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
1349
1349
  }
1350
1350
  .ds-247420 .gm-recall-hit {
1351
1351
  border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent);
1352
- border-radius: 6px;
1352
+ border-radius: var(--r-0);
1353
1353
  padding: 8px 10px;
1354
1354
  background: color-mix(in oklab, var(--bg) 92%, var(--fg) 2%);
1355
1355
  }
@@ -45,7 +45,7 @@
45
45
  }
46
46
  .sp-loading-bar-track {
47
47
  height: 6px;
48
- border-radius: 3px;
48
+ border-radius: var(--r-hair);
49
49
  background: var(--bg-3);
50
50
  overflow: hidden;
51
51
  }