anentrypoint-design 0.0.165 → 0.0.167

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.165",
3
+ "version": "0.0.167",
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",
@@ -34,9 +34,9 @@ import {
34
34
  ServerRail, ChannelItem, MemberList, MobileHeader,
35
35
  UserPanel, VoiceStrip, VoiceUser, ThreadPanel, ForumView, PageView, Banner,
36
36
  } from './components/community.js';
37
- import { VoiceControls } from './components/voice.js';
37
+ import { VoiceControls, VoiceSettingsModal, AudioQueue, PttButton, VadMeter, WebcamPreview } from './components/voice.js';
38
38
  import { ContextMenu } from './components/editor-primitives.js';
39
- import { EmojiPicker, CommandPalette } from './components/overlay-primitives.js';
39
+ import { EmojiPicker, CommandPalette, AuthModal, BootOverlay, SettingsPopover, VideoLightbox } from './components/overlay-primitives.js';
40
40
 
41
41
  const h = webjsx.createElement;
42
42
 
@@ -157,6 +157,9 @@ export function mountCommunityApp(root, adapter = {}) {
157
157
 
158
158
  const voiceView = (s) => h('div', { class: 'vx-view' },
159
159
  h('div', { class: 'vx-grid' }, ...(s.voiceParticipants || []).map((p, i) => VoiceUser({ ...p, key: p.identity || p.id || i }))),
160
+ s.webcamEnabled ? WebcamPreview({ videoStream: s.webcamStream, resolution: s.webcamResolution, fps: s.webcamFps, enabled: true }) : null,
161
+ s.pttUiMode === 'vad' ? VadMeter({ level: s.micRawLevel || 0, threshold: s.vadThreshold, onThresholdChange: (t) => A.setVadThreshold && A.setVadThreshold(t) }) : null,
162
+ s.pttUiMode === 'ptt' || s.pttUiMode == null ? PttButton({ state: s.isSpeaking ? 'live' : 'idle', mode: 'ptt', onHoldStart: () => A.pttStart && A.pttStart(), onHoldEnd: () => A.pttStop && A.pttStop() }) : null,
160
163
  VoiceControls({
161
164
  muted: !!s.micMuted, deafened: !!s.voiceDeafened,
162
165
  onMic: () => A.toggleMic && A.toggleMic(),
@@ -170,7 +173,10 @@ export function mountCommunityApp(root, adapter = {}) {
170
173
  const s = get();
171
174
  const ch = s.currentChannel || {};
172
175
  const inVoiceChannel = ch.type === 'voice';
173
- const bodyMain = inVoiceChannel ? voiceView(s) : chatView(s);
176
+ const bodyMain = inVoiceChannel ? voiceView(s)
177
+ : ch.type === 'forum' ? ForumView({ posts: s.forumPosts || [], onSelect: (id) => A.openThread && A.openThread(id), onNewPost: () => A.newForumPost && A.newForumPost() })
178
+ : ch.type === 'page' ? PageView({ title: ch.name, html: s.pageHtml || '', isAdmin: !!s.canManage, onEdit: () => A.editPage && A.editPage() })
179
+ : chatView(s);
174
180
  const showVoiceBanner = s.voiceConnected && s.voiceChannelName && !(inVoiceChannel && s.voiceChannelName === ch.name);
175
181
  return h('div', { class: 'ca-app' },
176
182
  // top bar (sole app chrome above the chat-head)
@@ -199,6 +205,14 @@ export function mountCommunityApp(root, adapter = {}) {
199
205
  ctx.open ? ContextMenu({ items: ctx.items, anchor: { x: ctx.x, y: ctx.y }, onClose: () => { ctx = { ...ctx, open: false }; render(); } }) : null,
200
206
  emoji.open ? EmojiPicker({ open: true, anchorX: emoji.x, anchorY: emoji.y, onSelect: (em) => { try { emoji.onSelect && emoji.onSelect(em); } catch (_) {} emoji = { ...emoji, open: false }; render(); }, onClose: () => { emoji = { ...emoji, open: false }; render(); } }) : null,
201
207
  palette.open ? CommandPalette({ open: true, items: palette.items, onSelect: (it) => { try { palette.onSelect && palette.onSelect(it); } catch (_) {} palette = { ...palette, open: false }; render(); }, onClose: () => { palette = { ...palette, open: false }; render(); } }) : null,
208
+ // global overlays (visibility driven by adapter snapshot)
209
+ s.showAuthModal ? AuthModal({ open: true, mode: s.authMode || 'extension', error: s.authError || '', busy: !!s.authBusy, onModeChange: (m) => A.setAuthMode && A.setAuthMode(m), onConnectExtension: () => A.authExtension && A.authExtension(), onGenerate: () => A.authGenerate && A.authGenerate(), onImport: (k) => A.authImport && A.authImport(k), onClose: () => A.closeAuth && A.closeAuth() }) : null,
210
+ BootOverlay({ progress: s.bootProgress || 0, phase: s.bootPhase || '', errored: !!s.bootErrored, visible: !!s.bootVisible }),
211
+ s.settingsOpen ? SettingsPopover({ open: true, anchorX: (s.settingsAnchor && s.settingsAnchor.x) || 0, anchorY: (s.settingsAnchor && s.settingsAnchor.y) || 0, sections: s.settingsSections || [], onClose: () => A.openSettings && A.openSettings() }) : null,
212
+ s.voiceSettingsOpen ? VoiceSettingsModal({ open: true, mode: s.voiceMode || 'ptt', inputId: s.inputDeviceId, outputId: s.outputDeviceId, inputDevices: s.inputDevices || [], outputDevices: s.outputDevices || [], vadThreshold: s.vadThreshold, rnnoise: !!s.rnnoiseEnabled, autoGain: !!s.autoGainEnabled, forceTurn: !!s.forceTurnEnabled, bitrate: s.voiceBitrate, volume: s.masterVolume, onChange: (p) => A.voiceSettingsChange && A.voiceSettingsChange(p), onSave: () => A.voiceSettingsSave && A.voiceSettingsSave(), onCancel: () => A.voiceSettingsClose && A.voiceSettingsClose(), onClose: () => A.voiceSettingsClose && A.voiceSettingsClose() }) : null,
213
+ s.videoLightbox && s.videoLightbox.open ? VideoLightbox({ open: true, src: s.videoLightbox.src, label: s.videoLightbox.label, onClose: () => A.closeVideoLightbox && A.closeVideoLightbox() }) : null,
214
+ (s.audioQueueItems && s.audioQueueItems.length) ? AudioQueue({ segments: s.audioQueueItems, currentSegmentId: s.audioQueueCurrentId, paused: !!s.audioQueuePaused, onReplay: (id) => A.replaySegment && A.replaySegment(id), onSkip: () => A.skipSegment && A.skipSegment(), onResume: () => A.resumeQueue && A.resumeQueue(), onPause: () => A.pauseQueue && A.pauseQueue() }) : null,
215
+ s.threadPanelOpen ? ThreadPanel({ threads: s.threads || [], activeId: s.activeThreadId, onSelect: (id) => A.selectThread && A.selectThread(id), onCreate: () => A.createThread && A.createThread(), onClose: () => A.closeThreadPanel && A.closeThreadPanel() }) : null,
202
216
  );
203
217
  };
204
218
 
package/src/index.js CHANGED
@@ -69,7 +69,8 @@ export {
69
69
  renderPageHtml,
70
70
  theme
71
71
  };
72
- export { applyTheme, getTheme, resolvedTheme, onThemeChange, initTheme } from './theme.js';
72
+ export { applyTheme, getTheme, resolvedTheme, onThemeChange, initTheme,
73
+ applyAccent, getAccent, applyDensity, getDensity } from './theme.js';
73
74
  export const h = webjsx.createElement;
74
75
  export const applyDiff = webjsx.applyDiff;
75
76
 
@@ -15,7 +15,7 @@
15
15
  margin: 0;
16
16
  max-height: 320px;
17
17
  overflow: auto;
18
- background: var(--os-bg-2, #F0E9DA);
18
+ background: var(--os-bg-2);
19
19
  padding: var(--space-2, 8px) var(--space-3, 16px);
20
20
  border-radius: var(--os-radius-sm, 6px);
21
21
  }
@@ -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, #857B6C); letter-spacing: var(--tr-label, 0.10em); text-transform: uppercase; }
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; }
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; }
@@ -38,14 +38,14 @@
38
38
  /* chatlog (legacy fd-chat-msgs container) */
39
39
  .fd-chatlog {
40
40
  max-height: 420px; overflow-y: auto;
41
- background: var(--os-bg-2, #F0E9DA);
41
+ background: var(--os-bg-2);
42
42
  border-radius: var(--os-radius-sm, 6px);
43
43
  padding: var(--space-1, 4px); margin-top: var(--space-2, 8px);
44
44
  }
45
- .fd-chatlog-msg { padding: var(--space-1, 4px) var(--space-3, 16px); background: var(--os-bg-2, #F0E9DA); white-space: pre-wrap; word-break: break-word; }
46
- .fd-chatlog-assistant { color: var(--os-accent, #3F8A4A); }
47
- .fd-chatlog-tool { margin: var(--space-1, 4px) 0; padding: var(--space-1, 4px) var(--space-2, 8px); background: var(--os-bg-3, #E3DAC7); border-radius: var(--os-radius-sm, 6px); font-family: var(--os-mono, JetBrains Mono, monospace); font-size: var(--fs-tiny, 12px); }
48
- .fd-chatlog-tool-sum { cursor: pointer; color: var(--os-red, #FF6B4A); padding: var(--space-1, 4px) 0; }
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
+ .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); }
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
 
51
51
  /* chip wraps (providers, env) */
@@ -1,31 +1,40 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
2
-
1
+ /* Fonts are declared once in the canonical theme (colors_and_type.css /
2
+ vendor/fonts.css), which every .ds-247420 consumer loads first. No @import
3
+ here — a second Inter-only import risked a weight-set FOUT mismatch. */
4
+
5
+ /* The OS shell namespaces its surfaces as --os-* but those are pure ALIASES of
6
+ the canonical semantic tokens from colors_and_type.css. colors_and_type.css
7
+ is always loaded before this sheet for any .ds-247420 consumer, so the
8
+ canonical tokens are guaranteed present and the alias fallbacks are dropped —
9
+ a fallback here would silently re-introduce theme drift (a baked light value
10
+ that ignores [data-theme="ink"]). One theme drives both token namespaces. */
3
11
  :root {
4
- --ff-ui: 'Inter', system-ui, sans-serif;
5
- --ff-display: 'Inter', system-ui, sans-serif;
6
- --ff-mono: 'JetBrains Mono', ui-monospace, monospace;
7
- --os-accent: var(--panel-accent, #3F8A4A);
8
- --os-accent-2: var(--panel-accent-2, #2B6B36);
9
- --os-accent-soft: var(--panel-select, #D8ECCB);
10
- --os-bg-0: var(--panel-0, #F5F0E4);
11
- --os-bg-1: var(--panel-1, #FBF6EB);
12
- --os-bg-2: var(--panel-2, #F0E9DA);
13
- --os-bg-3: var(--panel-3, #E3DAC7);
14
- --os-fg: var(--panel-text, #1F1B16);
15
- --os-fg-2: var(--panel-text-2, #5A5246);
16
- --os-fg-3: var(--panel-text-3, #857B6C);
17
- --os-red: var(--warn, #FF6B4A);
18
- --os-amber: var(--sun, #FFD86B);
19
- --os-green: var(--green, #3F8A4A);
20
- --os-radius: var(--r-2, 10px);
21
- --os-radius-sm: var(--r-1, 6px);
12
+ /* --ff-ui is the OS-shell alias for the canonical body font; --ff-display
13
+ and --ff-mono are already canonical (colors_and_type.css), referenced
14
+ directly below do not self-redefine them here (cycle). */
15
+ --ff-ui: var(--ff-body);
16
+ --os-accent: var(--accent);
17
+ --os-accent-2: var(--accent-bright, var(--accent));
18
+ --os-accent-soft: var(--accent-tint);
19
+ --os-bg-0: var(--bg);
20
+ --os-bg-1: var(--bg-2);
21
+ --os-bg-2: var(--bg-3);
22
+ --os-bg-3: var(--panel-3);
23
+ --os-fg: var(--fg);
24
+ --os-fg-2: var(--fg-2);
25
+ --os-fg-3: var(--fg-3);
26
+ --os-red: var(--warn);
27
+ --os-amber: var(--sun);
28
+ --os-green: var(--green);
29
+ --os-radius: var(--r-2);
30
+ --os-radius-sm: var(--r-1);
22
31
  --os-bar-h: 44px;
23
32
  --os-bar-h-mobile: 52px;
24
33
  --os-rail-w: 64px;
25
34
  --os-tap: 44px;
26
- --os-font: var(--ff-ui, 'Inter', system-ui, sans-serif);
27
- --os-display: var(--ff-display, 'Inter', system-ui, sans-serif);
28
- --os-mono: var(--ff-mono, 'JetBrains Mono', ui-monospace, monospace);
35
+ --os-font: var(--ff-ui);
36
+ --os-display: var(--ff-display);
37
+ --os-mono: var(--ff-mono);
29
38
  }
30
39
 
31
40
  html, body {
@@ -348,10 +357,10 @@ html, body {
348
357
  .app-pane.mono pre { background: var(--os-bg-2); padding: 10px 12px; margin: 8px 0 0 0; max-height: 220px; overflow: auto; white-space: pre-wrap; font: 11.5px var(--os-mono); border-radius: var(--r-1, 6px); color: var(--os-fg); border: none; }
349
358
  .app-shell-pane { margin: 0; padding: 8px; font: 12px var(--os-mono); color: var(--os-fg); background: var(--os-bg-0); height: 100%; overflow: auto; white-space: pre-wrap; box-sizing: border-box; }
350
359
  .app-canvas { width: 100%; height: 100%; background: var(--os-bg-0); display: block; cursor: default; }
351
- .app-canvas.x-display { background: #0b0d10; }
360
+ .app-canvas.x-display { background: #0b0d10; } /* intentional: fake CRT/terminal black screen, not a theme surface */
352
361
  .app-frame { width: 100%; height: 100%; border: 0; background: var(--os-bg-0); }
353
362
  .app-iframe { width: 100%; height: 100%; border: 0; display: block; }
354
- .app-iframe.web { background: #ffffff; }
363
+ .app-iframe.web { background: #ffffff; } /* intentional: white canvas for embedded external web content that expects white */
355
364
  .app-text-cursor { }
356
365
 
357
366
  @media (prefers-reduced-motion: no-preference) {
@@ -429,53 +438,45 @@ html, body {
429
438
  .wm-resize { display: none !important; }
430
439
  }
431
440
 
432
- /* ---- data-attr theme/density/accent rules (ported from anentrypoint-update colors_and_type.css) ---- */
433
- :root[data-theme="ink"] {
434
- --os-bg-0: #14131a;
435
- --os-bg-1: #1a1924;
436
- --os-bg-2: #20202a;
437
- --os-bg-3: #2a2a36;
438
- --os-fg: #efece4;
439
- --os-fg-2: #c8c5bc;
440
- --os-fg-3: #8c8a80;
441
- color-scheme: dark;
442
- }
443
- :root[data-theme="paper"] {
444
- --os-bg-0: #f6f5f1;
445
- --os-bg-1: #efece4;
446
- --os-bg-2: #e7e3d8;
447
- --os-bg-3: #d8d3c4;
448
- --os-fg: #14131a;
449
- --os-fg-2: #3a3833;
450
- --os-fg-3: #6a6660;
451
- color-scheme: light;
452
- }
453
- :root[data-density="compact"] { --os-bar-h: 28px; --os-tile-pad: 6px; --os-gap: 6px; }
441
+ /* ---- data-attr theme/accent: deferred to the canonical theme ----
442
+ * The OS shell no longer redefines surface or accent colors per theme. The
443
+ * --os-* aliases above consume the canonical semantic tokens (--bg/--fg/
444
+ * --accent), and colors_and_type.css already drives [data-theme] (paper/ink/
445
+ * auto, with color-scheme + --danger tuning) and [data-accent] (green/purple/
446
+ * mascot). Re-declaring --os-bg-*/--os-accent per theme here only re-introduced
447
+ * drift (ink #14131a vs canonical #131318; purple #7c5cff vs canonical
448
+ * #420247). Density bar-height is genuinely OS-shell-specific, so it stays;
449
+ * --os-accent-tint maps to the canonical accent tint. */
450
+ :root { --os-accent-tint: var(--accent-tint); }
451
+ :root[data-density="compact"] { --os-bar-h: 28px; --os-tile-pad: 6px; --os-gap: 6px; }
454
452
  :root[data-density="comfortable"] { --os-bar-h: 36px; --os-tile-pad: 10px; --os-gap: 10px; }
455
- :root[data-density="spacious"] { --os-bar-h: 44px; --os-tile-pad: 14px; --os-gap: 14px; }
456
- :root[data-accent="green"] { --os-accent: #247420; --os-accent-tint: color-mix(in oklab, #247420 18%, transparent); }
457
- :root[data-accent="purple"] { --os-accent: #7c5cff; --os-accent-tint: color-mix(in oklab, #7c5cff 18%, transparent); }
458
- :root[data-accent="mascot"] { --os-accent: #ff6d3f; --os-accent-tint: color-mix(in oklab, #ff6d3f 18%, transparent); }
459
- :root[data-theme="ink"][data-accent="green"] { --os-accent: #3FA93A; }
460
- :root[data-theme="ink"][data-accent="purple"] { --os-accent: #a085ff; }
461
- :root[data-theme="ink"][data-accent="mascot"] { --os-accent: #ff8a64; }
453
+ :root[data-density="spacious"] { --os-bar-h: 44px; --os-tile-pad: 14px; --os-gap: 14px; }
462
454
 
463
455
  /* ============================================================
464
- * thebird theme preset (migrated from thebird's local thebird-brand.css
456
+ * thebird brand layer (migrated from thebird's local thebird-brand.css
465
457
  * 2026-05-26). thebird ships ZERO design CSS — every rule below lives here
466
458
  * upstream and is delivered via the published package. Scoped to .ds-247420
467
- * (thebird's OS root carries that class). Brand identity: Inter +
468
- * --paper #F5F0E4 + green accent #247420 + uniform 34px bars +
469
- * Windows-style right-side window controls.
459
+ * (thebird's OS root carries that class). Brand identity: Inter + green accent
460
+ * + uniform 34px bars + Windows-style right-side window controls.
461
+ *
462
+ * NOTE: this no longer globally overrides --paper. A global :root override
463
+ * silently mutated the base theme for EVERY portfolio consumer (canonical
464
+ * --paper is #F6F5F1; thebird wanted #F5F0E4). The warm-paper variant is now a
465
+ * named preset [data-theme="thebird"] a consumer opts into, leaving the base
466
+ * theme untouched. Typography + bar geometry below are brand chrome, not
467
+ * color, so they stay scoped to .ds-247420.
470
468
  * ============================================================ */
471
- :root {
472
- --paper: #F5F0E4;
469
+ [data-theme="thebird"] {
470
+ color-scheme: light;
471
+ --paper: #F5F0E4;
472
+ --paper-2: #EFE9DB;
473
+ --paper-3: #E3DAC7;
474
+ --bg: var(--paper); --bg-2: var(--paper-2); --bg-3: var(--paper-3);
475
+ --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
476
+ --accent: var(--green); --accent-fg: var(--paper);
473
477
  }
474
478
  .ds-247420 {
475
- --ff-ui: 'Inter', system-ui, sans-serif !important;
476
- --ff-display: 'Inter', system-ui, sans-serif !important;
477
- --ff-prose: 'Inter', system-ui, sans-serif !important;
478
- --os-accent: #247420;
479
+ --ff-ui: var(--ff-body);
479
480
  /* uniform bar height: 22px button + 6px+6px padding = 34px */
480
481
  --os-bar-h: 34px !important;
481
482
  --os-bar-h-mobile: 34px !important;
@@ -518,8 +519,8 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
518
519
  position: fixed;
519
520
  pointer-events: none;
520
521
  z-index: 9050;
521
- background: color-mix(in oklab, var(--os-accent, #247420) 20%, transparent);
522
- border: 2px solid var(--os-accent, #247420);
522
+ background: color-mix(in oklab, var(--os-accent) 20%, transparent);
523
+ border: 2px solid var(--os-accent);
523
524
  border-radius: 8px;
524
525
  transition: all 120ms ease;
525
526
  }
@@ -534,14 +535,14 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
534
535
  top: 50%;
535
536
  transform: translate(-50%, -50%);
536
537
  padding: 16px 20px;
537
- background: var(--os-bg-2, #1a1a1a);
538
- border: 1px solid var(--os-accent, #247420);
538
+ background: var(--os-bg-2);
539
+ border: 1px solid var(--os-accent);
539
540
  border-radius: 8px;
540
541
  z-index: 9600;
541
- font-family: var(--ff-ui, 'Inter', sans-serif);
542
- color: var(--os-fg, #fff);
542
+ font-family: var(--ff-ui);
543
+ color: var(--os-fg);
543
544
  min-width: 280px;
544
- box-shadow: 0 12px 40px rgba(0,0,0,0.5);
545
+ box-shadow: var(--shadow-overlay);
545
546
  }
546
547
  .ds-247420 .wm-switcher-item {
547
548
  padding: 8px 12px;
@@ -551,8 +552,8 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
551
552
  gap: 10px;
552
553
  }
553
554
  .ds-247420 .wm-switcher-item.active {
554
- background: var(--os-accent, #247420);
555
- color: var(--paper, #fff);
555
+ background: var(--os-accent);
556
+ color: var(--paper);
556
557
  }
557
558
 
558
559
  /* freddie-chat font family (upstream still ships Nunito; brand is Inter). */
@@ -560,7 +561,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
560
561
  .ds-247420 freddie-chat .chat-bubble,
561
562
  .ds-247420 freddie-chat .chat-meta,
562
563
  .ds-247420 freddie-chat .chat-head {
563
- font-family: var(--ff-ui, 'Inter', system-ui, sans-serif);
564
+ font-family: var(--ff-ui);
564
565
  }
565
566
  .ds-247420 freddie-chat .chat-bubble pre,
566
567
  .ds-247420 freddie-chat .chat-bubble code {
@@ -587,31 +588,31 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
587
588
  display: inline-flex; align-items: center; gap: 6px;
588
589
  height: 22px; padding: 0 6px 0 8px;
589
590
  border-radius: var(--r-pill, 999px);
590
- background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent);
591
- color: var(--fg, #1a1a1a);
592
- font-family: var(--ff-ui, system-ui); font-size: 11px; font-weight: 500;
591
+ background: color-mix(in oklab, var(--fg) 6%, transparent);
592
+ color: var(--fg);
593
+ font-family: var(--ff-ui); font-size: 11px; font-weight: 500;
593
594
  cursor: pointer;
594
595
  border: 1px solid transparent;
595
596
  transition: background 120ms ease, border-color 120ms ease;
596
597
  user-select: none; flex: 0 0 auto;
597
598
  }
598
- .ds-247420 .tb-sess-chip:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent); }
599
+ .ds-247420 .tb-sess-chip:hover { background: color-mix(in oklab, var(--fg) 12%, transparent); }
599
600
  .ds-247420 .tb-sess-chip.active {
600
- background: color-mix(in oklab, var(--os-accent, #247420) 18%, transparent);
601
- border-color: var(--os-accent, #247420);
602
- color: var(--fg, #1a1a1a);
601
+ background: color-mix(in oklab, var(--os-accent) 18%, transparent);
602
+ border-color: var(--os-accent);
603
+ color: var(--fg);
603
604
  }
604
- .ds-247420 .tb-sess-chip.active .tb-sess-dot { background: var(--os-accent, #247420); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
605
- .ds-247420 .tb-sess-dot { width: 6px; height: 6px; border-radius: 50%; background: color-mix(in oklab, var(--fg, #1a1a1a) 40%, transparent); flex: 0 0 6px; }
605
+ .ds-247420 .tb-sess-chip.active .tb-sess-dot { background: var(--os-accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent) 30%, transparent); }
606
+ .ds-247420 .tb-sess-dot { width: 6px; height: 6px; border-radius: 50%; background: color-mix(in oklab, var(--fg) 40%, transparent); flex: 0 0 6px; }
606
607
  .ds-247420 .tb-sess-label { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
607
608
  .ds-247420 .tb-sess-badge {
608
609
  display: inline-flex; align-items: center; justify-content: center;
609
610
  min-width: 16px; height: 14px; padding: 0 4px;
610
611
  border-radius: 7px;
611
- background: color-mix(in oklab, var(--fg, #1a1a1a) 14%, transparent);
612
+ background: color-mix(in oklab, var(--fg) 14%, transparent);
612
613
  font-size: 9px; font-weight: 600; line-height: 1;
613
614
  }
614
- .ds-247420 .tb-sess-chip.active .tb-sess-badge { background: color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
615
+ .ds-247420 .tb-sess-chip.active .tb-sess-badge { background: color-mix(in oklab, var(--os-accent) 30%, transparent); }
615
616
  .ds-247420 .tb-sess-x {
616
617
  width: 16px; height: 16px; line-height: 14px; text-align: center;
617
618
  border: 0; padding: 0; background: transparent;
@@ -620,45 +621,45 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
620
621
  opacity: 0.55; transition: opacity 120ms ease, background 120ms ease;
621
622
  }
622
623
  .ds-247420 .tb-sess-chip:hover .tb-sess-x { opacity: 1; }
623
- .ds-247420 .tb-sess-x:hover { background: color-mix(in oklab, #d33 30%, transparent); color: #fff; }
624
+ .ds-247420 .tb-sess-x:hover { background: color-mix(in oklab, var(--danger) 30%, transparent); color: var(--on-color); }
624
625
 
625
626
  .ds-247420 .tb-sess-add {
626
627
  display: inline-flex; align-items: center; gap: 4px;
627
628
  height: 22px; padding: 0 10px;
628
- border: 1px dashed color-mix(in oklab, var(--fg, #1a1a1a) 30%, transparent);
629
+ border: 1px dashed color-mix(in oklab, var(--fg) 30%, transparent);
629
630
  background: transparent;
630
631
  border-radius: var(--r-pill, 999px);
631
- font-family: var(--ff-ui, system-ui); font-size: 11px; font-weight: 500;
632
- color: var(--fg, #1a1a1a);
632
+ font-family: var(--ff-ui); font-size: 11px; font-weight: 500;
633
+ color: var(--fg);
633
634
  cursor: pointer;
634
635
  margin-left: 6px;
635
636
  transition: border-color 120ms ease, background 120ms ease;
636
637
  }
637
638
  .ds-247420 .tb-sess-add:hover {
638
- border-color: var(--os-accent, #247420);
639
- background: color-mix(in oklab, var(--os-accent, #247420) 8%, transparent);
639
+ border-color: var(--os-accent);
640
+ background: color-mix(in oklab, var(--os-accent) 8%, transparent);
640
641
  }
641
642
  .ds-247420 .tb-sess-add-plus { font-size: 13px; line-height: 1; }
642
643
  .ds-247420 .tb-sess-add-lbl { line-height: 1; }
643
644
 
644
645
  .tb-sess-overlay {
645
646
  position: fixed; inset: 0; z-index: 9800;
646
- background: color-mix(in oklab, #000 40%, transparent);
647
+ background: var(--scrim);
647
648
  display: flex; align-items: center; justify-content: center;
648
649
  animation: tb-sess-fade 120ms ease;
649
650
  }
650
651
  @keyframes tb-sess-fade { from { opacity: 0; } to { opacity: 1; } }
651
652
  .tb-sess-modal {
652
- background: var(--bg, #f5f0e4);
653
- color: var(--fg, #1a1a1a);
653
+ background: var(--bg);
654
+ color: var(--fg);
654
655
  border-radius: 12px;
655
- box-shadow: 0 12px 40px color-mix(in oklab, #000 30%, transparent);
656
+ box-shadow: var(--shadow-overlay);
656
657
  min-width: 320px; max-width: 480px;
657
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent);
658
+ border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
658
659
  overflow: hidden;
659
- font-family: var(--ff-ui, system-ui);
660
+ font-family: var(--ff-ui);
660
661
  }
661
- .tb-sess-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 8%, transparent); }
662
+ .tb-sess-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
662
663
  .tb-sess-modal-title { font-weight: 600; font-size: 14px; }
663
664
  .tb-sess-modal-x { background: transparent; border: 0; font-size: 20px; line-height: 1; cursor: pointer; color: inherit; padding: 0 4px; }
664
665
  .tb-sess-modal-body { padding: 16px; display: flex; flex-direction: column; gap: 8px; }
@@ -666,28 +667,28 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
666
667
  .tb-sess-modal-input {
667
668
  width: 100%; box-sizing: border-box;
668
669
  height: 32px; padding: 0 10px;
669
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent);
670
+ border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
670
671
  border-radius: 6px;
671
- background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, var(--bg, #fff));
672
+ background: color-mix(in oklab, var(--fg) 6%, var(--bg));
672
673
  color: inherit;
673
674
  font-family: inherit; font-size: 13px;
674
675
  }
675
- .tb-sess-modal-input:focus { outline: none; border-color: var(--os-accent, #247420); box-shadow: 0 0 0 3px color-mix(in oklab, var(--os-accent, #247420) 20%, transparent); }
676
+ .tb-sess-modal-input:focus { outline: none; border-color: var(--os-accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--os-accent) 20%, transparent); }
676
677
  .tb-sess-modal-hint { font-size: 11px; opacity: 0.7; }
677
678
  .tb-sess-modal-msg { font-size: 13px; }
678
- .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, #1a1a1a) 8%, transparent); }
679
+ .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); }
679
680
  .tb-sess-modal-btn {
680
681
  height: 28px; padding: 0 14px;
681
- border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent);
682
+ border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
682
683
  background: transparent; color: inherit;
683
684
  font-family: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
684
685
  transition: background 120ms ease, border-color 120ms ease;
685
686
  }
686
- .tb-sess-modal-btn:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
687
- .tb-sess-modal-btn.primary { background: var(--os-accent, #247420); color: #fff; border-color: var(--os-accent, #247420); }
688
- .tb-sess-modal-btn.primary:hover { background: color-mix(in oklab, var(--os-accent, #247420) 80%, #000); }
689
- .tb-sess-modal-btn.danger { background: #d33; color: #fff; border-color: #d33; }
690
- .tb-sess-modal-btn.danger:hover { background: #b22; }
687
+ .tb-sess-modal-btn:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
688
+ .tb-sess-modal-btn.primary { background: var(--os-accent); color: var(--on-color); border-color: var(--os-accent); }
689
+ .tb-sess-modal-btn.primary:hover { background: color-mix(in oklab, var(--os-accent) 80%, var(--ink)); }
690
+ .tb-sess-modal-btn.danger { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
691
+ .tb-sess-modal-btn.danger:hover { background: color-mix(in oklab, var(--danger) 80%, var(--ink)); }
691
692
 
692
693
  .tb-sess-empty {
693
694
  position: fixed; inset: 0; z-index: 8900;
@@ -696,65 +697,65 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
696
697
  }
697
698
  .tb-sess-empty-card {
698
699
  pointer-events: auto;
699
- background: var(--bg, #f5f0e4);
700
- color: var(--fg, #1a1a1a);
701
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 14%, transparent);
700
+ background: var(--bg);
701
+ color: var(--fg);
702
+ border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent);
702
703
  border-radius: 16px;
703
- box-shadow: 0 8px 32px color-mix(in oklab, #000 14%, transparent);
704
+ box-shadow: var(--shadow-3);
704
705
  padding: 32px 40px; text-align: center;
705
- font-family: var(--ff-ui, system-ui);
706
+ font-family: var(--ff-ui);
706
707
  max-width: 420px;
707
708
  }
708
709
  .tb-sess-empty-title { font-size: 18px; font-weight: 600; margin-bottom: 6px; }
709
710
  .tb-sess-empty-sub { font-size: 13px; opacity: 0.7; margin-bottom: 20px; }
710
711
  .tb-sess-empty-cta {
711
712
  height: 40px; padding: 0 24px;
712
- background: var(--os-accent, #247420); color: #fff;
713
+ background: var(--os-accent); color: var(--on-color);
713
714
  border: 0; border-radius: 999px;
714
715
  font-family: inherit; font-size: 14px; font-weight: 600;
715
716
  cursor: pointer;
716
717
  transition: transform 120ms ease, box-shadow 120ms ease;
717
718
  }
718
- .tb-sess-empty-cta:hover { transform: translateY(-1px); box-shadow: 0 4px 16px color-mix(in oklab, var(--os-accent, #247420) 40%, transparent); }
719
+ .tb-sess-empty-cta:hover { transform: translateY(-1px); box-shadow: 0 4px 16px color-mix(in oklab, var(--os-accent) 40%, transparent); }
719
720
 
720
721
  /* ---- Workspaces app — full-window session manager card grid ---- */
721
- .ds-247420 .tb-sessions-app { display: flex; flex-direction: column; height: 100%; font-family: var(--ff-ui, system-ui); color: var(--fg, #1a1a1a); background: var(--bg, #f5f0e4); }
722
- .ds-247420 .tb-sessions-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 10%, transparent); }
722
+ .ds-247420 .tb-sessions-app { display: flex; flex-direction: column; height: 100%; font-family: var(--ff-ui); color: var(--fg); background: var(--bg); }
723
+ .ds-247420 .tb-sessions-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid color-mix(in oklab, var(--fg) 10%, transparent); }
723
724
  .ds-247420 .tb-sessions-title { font-weight: 600; font-size: 14px; }
724
725
  .ds-247420 .tb-sessions-count { font-size: 12px; opacity: 0.6; margin-left: 4px; }
725
726
  .ds-247420 .tb-sessions-spacer { flex: 1; }
726
- .ds-247420 .tb-sessions-btn { height: 28px; padding: 0 12px; border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent); background: transparent; color: inherit; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit; }
727
- .ds-247420 .tb-sessions-btn:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
728
- .ds-247420 .tb-sessions-btn.primary { background: var(--os-accent, #247420); color: #fff; border-color: var(--os-accent, #247420); }
729
- .ds-247420 .tb-sessions-btn.danger { background: #d33; color: #fff; border-color: #d33; }
727
+ .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; }
728
+ .ds-247420 .tb-sessions-btn:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
729
+ .ds-247420 .tb-sessions-btn.primary { background: var(--os-accent); color: var(--on-color); border-color: var(--os-accent); }
730
+ .ds-247420 .tb-sessions-btn.danger { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
730
731
  .ds-247420 .tb-sessions-btn:disabled { opacity: 0.4; cursor: not-allowed; }
731
732
  .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; }
732
- .ds-247420 .tb-sessions-card { padding: 12px; border-radius: 10px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent); background: color-mix(in oklab, var(--fg, #1a1a1a) 3%, transparent); display: flex; flex-direction: column; gap: 8px; transition: border-color 120ms ease, transform 120ms ease; }
733
- .ds-247420 .tb-sessions-card:hover { border-color: var(--os-accent, #247420); }
734
- .ds-247420 .tb-sessions-card.active { border-color: var(--os-accent, #247420); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
733
+ .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; }
734
+ .ds-247420 .tb-sessions-card:hover { border-color: var(--os-accent); }
735
+ .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); }
735
736
  .ds-247420 .tb-sessions-card-head { display: flex; align-items: center; gap: 8px; }
736
737
  .ds-247420 .tb-sessions-card-check { width: 14px; height: 14px; cursor: pointer; flex: 0 0 14px; }
737
738
  .ds-247420 .tb-sessions-card-name { font-weight: 600; font-size: 13px; flex: 1; outline: none; padding: 2px 4px; border-radius: 4px; }
738
- .ds-247420 .tb-sessions-card-name[contenteditable="true"] { background: color-mix(in oklab, var(--fg, #1a1a1a) 8%, transparent); }
739
+ .ds-247420 .tb-sessions-card-name[contenteditable="true"] { background: color-mix(in oklab, var(--fg) 8%, transparent); }
739
740
  .ds-247420 .tb-sessions-card-id { font-family: var(--os-mono, monospace); font-size: 10px; opacity: 0.5; }
740
741
  .ds-247420 .tb-sessions-card-stats { font-size: 11px; opacity: 0.7; display: flex; gap: 12px; }
741
742
  .ds-247420 .tb-sessions-card-actions { display: flex; gap: 6px; margin-top: 4px; }
742
- .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, #1a1a1a) 16%, transparent); background: transparent; color: inherit; cursor: pointer; font-family: inherit; }
743
- .ds-247420 .tb-sessions-card-actions button:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
744
- .ds-247420 .tb-sessions-card-actions button.danger:hover { background: #d33; color: #fff; border-color: #d33; }
743
+ .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; }
744
+ .ds-247420 .tb-sessions-card-actions button:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
745
+ .ds-247420 .tb-sessions-card-actions button.danger:hover { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
745
746
  .ds-247420 .tb-sessions-empty-mid { padding: 40px; text-align: center; opacity: 0.6; font-size: 13px; }
746
747
 
747
748
  /* ---- prefers-contrast: more — strengthen borders + focus so the translucent
748
749
  chrome stays legible under forced/high-contrast user settings. ---- */
749
750
  @media (prefers-contrast: more) {
750
- .ds-247420 .wm-win { border-color: var(--fg, #1a1a1a); }
751
- .ds-247420 .wm-bar { border-bottom: 1px solid var(--fg, #1a1a1a); }
751
+ .ds-247420 .wm-win { border-color: var(--fg); }
752
+ .ds-247420 .wm-bar { border-bottom: 1px solid var(--fg); }
752
753
  .ds-247420 .os-menubar,
753
- .ds-247420 .os-taskbar { border-color: var(--fg, #1a1a1a); }
754
+ .ds-247420 .os-taskbar { border-color: var(--fg); }
754
755
  .ds-247420 .tb-sess-chip,
755
756
  .ds-247420 .tb-sessions-card,
756
- .ds-247420 .tb-sessions-btn { border-color: var(--fg, #1a1a1a); }
757
- .ds-247420 :focus-visible { outline: 2px solid var(--fg, #1a1a1a); outline-offset: 2px; }
757
+ .ds-247420 .tb-sessions-btn { border-color: var(--fg); }
758
+ .ds-247420 :focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }
758
759
  }
759
760
 
760
761
  /* ---- print: a web-OS desktop has no meaningful print form. Suppress the
@@ -763,6 +764,6 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
763
764
  .os-menubar, .os-taskbar, .wm-snap-preview,
764
765
  .tb-sess-overlay, .tb-switching, .wm-switcher { display: none !important; }
765
766
  .wm-root, .wm-canvas { position: static !important; transform: none !important; overflow: visible !important; }
766
- .wm-win { position: static !important; box-shadow: none !important; border: 1px solid #000 !important; page-break-inside: avoid; margin: 0 0 12px; width: auto !important; height: auto !important; }
767
+ .wm-win { position: static !important; box-shadow: none !important; border: 1px solid var(--fg) !important; page-break-inside: avoid; margin: 0 0 12px; width: auto !important; height: auto !important; }
767
768
  .wm-win.wm-min { display: none !important; }
768
769
  }
package/src/page-html.js CHANGED
@@ -93,9 +93,21 @@ ${cssLink}
93
93
  { "imports": { "anentrypoint-design": "https://unpkg.com/anentrypoint-design@latest/dist/247420.js" } }
94
94
  </script>
95
95
  <style>
96
- .app-stage { max-width: 1100px; margin: 0 auto; padding: 24px; display: grid; gap: 24px }
97
- .page-body h1 { margin-top: 0 } .page-body h2 { margin-top: 32px } .page-body h3 { margin-top: 24px }
98
- .page-body pre { margin: 12px 0; background: var(--panel-2); padding: 12px; border-radius: 8px; overflow-x: auto }
96
+ .app-stage { width: 100%; max-width: var(--measure-wide, 940px); margin-inline: auto; padding: var(--space-6, 48px) var(--space-4, 24px) var(--space-8, 96px); display: grid; gap: var(--space-6, 48px); box-sizing: border-box }
97
+ @media (max-width: 768px) { .app-stage { padding: var(--space-4, 24px) var(--space-3, 16px) var(--space-6, 48px); gap: var(--space-5, 32px) } }
98
+ .page-body > :first-child { margin-top: 0 }
99
+ .page-body h1 { margin-top: 0 } .page-body h2 { margin-top: var(--space-5, 32px) } .page-body h3 { margin-top: var(--space-4, 24px) }
100
+ .page-body > * + * { margin-top: var(--space-3, 16px) }
101
+ .page-body pre { margin: var(--space-3, 16px) 0; background: var(--panel-2); padding: var(--space-3, 16px); border-radius: var(--r-1, 10px); overflow-x: auto }
102
+ /* .app-stage owns inter-block rhythm via grid gap; sections/hero must not double it */
103
+ .app-stage > .ds-hero { margin: 0; padding: 0 }
104
+ .app-stage > .ds-section { margin: 0 }
105
+ .app-stage .row + .row { margin-top: var(--space-1, 4px) }
106
+ .app-stage .ds-section .row { margin-top: var(--space-2, 8px) }
107
+ .app-stage .ds-section > p.ds-lede { margin: 0 0 var(--space-3, 16px); max-width: var(--measure, 68ch); color: var(--fg-2) }
108
+ .row-benefit { font-style: italic; color: var(--fg-3); font-size: var(--fs-sm); margin-top: var(--space-1, 4px) }
109
+ .ds-row-arrow { margin-left: auto; opacity: .5; transition: opacity var(--dur-snap, 80ms) var(--ease) }
110
+ a.row:hover .ds-row-arrow { opacity: 1 }
99
111
  </style>
100
112
  <script id="__site__" type="application/json">${JSON.stringify(pageData).replace(/</g, '\\u003c')}</script>
101
113
  ${headExtra}