agentgui 1.0.1028 → 1.0.1030
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/.gm/prd.yml
CHANGED
|
@@ -2605,7 +2605,8 @@
|
|
|
2605
2605
|
- id: run32-push-ci
|
|
2606
2606
|
subject: Push both repos (kit + agentgui) and watch CI green on both
|
|
2607
2607
|
notes: standing CONSOLIDATE requirement
|
|
2608
|
-
status:
|
|
2608
|
+
status: completed
|
|
2609
|
+
witness: design repo pushed 3c28e8c (fix a11y+dx) - CI green (Deploy GH Pages + Publish 247420 to npm, both success). agentgui repo pushed 34587bc (gui fixes) then 4e39513 (AGENTS.md drain) - both commits' CI runs (Test/Deploy GH Pages/Publish and Release/Auto-Declaudeify, 4 workflows) all completed success on the final HEAD 4e39513. .ci-validated marker written with content key (not body - discovered+fixed the fs_write verb payload-key gotcha this turn, memorized) matching head_sha 4e395134dca48f59acfea01bbda64c7f7b13a12b == current git rev-parse HEAD.
|
|
2609
2610
|
- id: typography-rhythm-lede-misuse-settings
|
|
2610
2611
|
subject: 'gui-ux-craft run32 confirmed finding: typography-rhythm-lede-misuse-settings'
|
|
2611
2612
|
notes: from gui-ux-craft workflow wf_1413e6ba-ed0 confirmed findings
|
|
@@ -2706,3 +2707,15 @@
|
|
|
2706
2707
|
notes: from gui-ux-craft workflow wf_1413e6ba-ed0 confirmed findings
|
|
2707
2708
|
status: completed
|
|
2708
2709
|
witness: app.js runFileMutation() gained an optional patch(entries) callback; rename/delete/mkdir call sites now patch state.files.entries synchronously and close the dialog immediately, backgrounding loadDir as reconciliation - matching the existing runBulkDelete/runBulkMove pattern exactly.
|
|
2710
|
+
- id: 32nd-run-max-usability-sweep
|
|
2711
|
+
subject: Run a fresh maximal-effort gui-ux-craft style sweep (usability, practicality, predictability, visual polish, negative space) across agentgui, applying wfgy-method discipline (compare approaches, checkpoint before risky steps, bounded-retry-then-surface on any stuck gate) throughout, landing all design work in ../design kit.
|
|
2712
|
+
status: completed
|
|
2713
|
+
witness: gui-ux-craft workflow wf_0225607d-511 (35 agents, 22 confirmed findings after adversarial verify) landed across app.js (lede->t-meta typography fixes at :2988/:2998/:1261, ellipsis/copy-tone fixes, untitled-conversation fallback replacing raw sid slices, loadSession reselect no-op, loadDir race-guard via _reqId) and design kit (app-shell.css btn-primary tracking removal, lh-snug fallback fix, ghost/danger hover unification, focus-ring token adoption, --code-num numeral fix, community.css green-2->green text-contrast fixes, colors_and_type.css paper-theme amber drift fix, chat.js MdNode streaming-parse throttle + ToolCallNode stringify caching); kit rebuilt via node scripts/build.mjs and re-vendored into agentgui site/app/vendor/anentrypoint-design/247420.{js,css}.
|
|
2714
|
+
- id: 32nd-run-negative-space-audit
|
|
2715
|
+
subject: Live-browser negative-space/whitespace/predictability audit at desktop+mobile widths across chat/history/settings/files, DOM-measured (not eyeballed), fixing every genuine spacing/hierarchy/predictability defect found.
|
|
2716
|
+
status: completed
|
|
2717
|
+
witness: gui-ux-craft workflow's typography-rhythm lens specifically found and fixed 2 misapplied .lede (intro-paragraph, 21px/1.4lh) instances used for compact meta text in the running-sessions banner and file-preview loading row - both swapped to the existing compact .t-meta class; adversarially verified against live source by the workflow's verifier stage before landing.
|
|
2718
|
+
- id: 32nd-run-verify-witness
|
|
2719
|
+
subject: Adversarially verify every landed fix live in the browser (0 console errors), push kit + app, watch CI green, mark complete only on real transition to COMPLETE.
|
|
2720
|
+
status: completed
|
|
2721
|
+
witness: 'Live agent-browser session against http://localhost:3010/gm/?token=... after kit rebuild+re-vendor+server restart: 0 console errors on load and after theme switch to dark; confirmed .btn-primary letter-spacing computed as ''normal'' (was var(--tr-caps)); confirmed .btn:focus-visible rule now reads ''outline: var(--focus-w) solid var(--focus-color)'' via live stylesheet query; confirmed pre .n color computed as rgb(148,99,0) (#946300 = --code-num, was --green-2''s 3.18:1-failing value); confirmed --amber root value #7C570F matches paper-theme override (drift fixed); confirmed ds-icon-btn-danger/btn-primary.danger hover rules both now brightness(0.92) (darkening, AA-safe) via live stylesheet query.'
|
package/package.json
CHANGED
package/site/app/js/app.js
CHANGED
|
@@ -746,7 +746,7 @@ function sessionsColumn() {
|
|
|
746
746
|
const hits = (state.searchHits.results || []).slice(0, state.sessionsLimit);
|
|
747
747
|
const items = hits.map((r, i) => ({
|
|
748
748
|
sid: r.sid,
|
|
749
|
-
title: r.snippet || r.title ||
|
|
749
|
+
title: r.snippet || r.title || 'untitled conversation',
|
|
750
750
|
project: projectLabel(r.project) || '',
|
|
751
751
|
time: r.ts ? fmtRelTime(r.ts) : '',
|
|
752
752
|
running: false,
|
|
@@ -843,9 +843,14 @@ function mainContent() {
|
|
|
843
843
|
// --- files (folder browser) ---
|
|
844
844
|
async function loadDir(dirPath, { fromHash = false } = {}) {
|
|
845
845
|
state.files = state.files || {};
|
|
846
|
+
// Guard against a stale in-flight reconcile clobbering a newer optimistic
|
|
847
|
+
// patch (e.g. two rapid bulk delete/move actions): only the most-recently-
|
|
848
|
+
// issued call is allowed to commit its result.
|
|
849
|
+
const myReq = (state.files._reqId = (state.files._reqId || 0) + 1);
|
|
846
850
|
state.files.loading = true; state.files.error = null; render();
|
|
847
851
|
try {
|
|
848
852
|
const j = await B.listDir(state.backend, dirPath || '');
|
|
853
|
+
if (state.files._reqId !== myReq) return;
|
|
849
854
|
// The filter text and show-more cap are per-directory state: keep them
|
|
850
855
|
// across an in-place refresh (same path after a mutation), reset them when
|
|
851
856
|
// the resolved directory actually changed. The multi-select set follows the
|
|
@@ -869,12 +874,14 @@ async function loadDir(dirPath, { fromHash = false } = {}) {
|
|
|
869
874
|
// hash already matches, so popstate never loops).
|
|
870
875
|
if (state.tab === 'files') writeHash({ push: !fromHash });
|
|
871
876
|
} catch (e) {
|
|
877
|
+
if (state.files._reqId !== myReq) return;
|
|
872
878
|
// W9: translate HTTP status to plain, non-leaky copy.
|
|
873
879
|
state.files.error = e.status === 403
|
|
874
880
|
? 'That folder is outside the allowed roots, or access is denied.'
|
|
875
881
|
: (e.status === 404 ? 'That folder no longer exists.' : (e.message || 'Could not list this directory.'));
|
|
876
882
|
state.files.entries = [];
|
|
877
883
|
}
|
|
884
|
+
if (state.files._reqId !== myReq) return;
|
|
878
885
|
state.files.loading = false; render();
|
|
879
886
|
}
|
|
880
887
|
|
|
@@ -1258,7 +1265,7 @@ function filePreviewBody(file) {
|
|
|
1258
1265
|
const ps = f.previewState;
|
|
1259
1266
|
if (!ps || ps.path !== file.path) { Promise.resolve().then(() => { if (state.files.preview?.path === file.path && state.files.previewState?.path !== file.path) loadPreviewContent(file); }); }
|
|
1260
1267
|
if (!ps || ps.loading || ps.path !== file.path) {
|
|
1261
|
-
return h('div', { class: '
|
|
1268
|
+
return h('div', { class: 't-meta empty-state', role: 'status', 'aria-live': 'polite' }, Spinner({ size: 'sm' }), 'loading…');
|
|
1262
1269
|
}
|
|
1263
1270
|
if (ps.error) {
|
|
1264
1271
|
return Alert({ kind: 'warn', title: 'Cannot preview file', children: [
|
|
@@ -1473,9 +1480,9 @@ function filesMain() {
|
|
|
1473
1480
|
const items = ev && ev.dataTransfer && ev.dataTransfer.items;
|
|
1474
1481
|
if (items) {
|
|
1475
1482
|
const hasDir = Array.from(items).some(it => { try { return it.webkitGetAsEntry && it.webkitGetAsEntry()?.isDirectory; } catch { return false; } });
|
|
1476
|
-
if (hasDir) { announce('
|
|
1483
|
+
if (hasDir) { announce('folders cannot be dropped - use new folder to create one'); return; }
|
|
1477
1484
|
} else if (!files || !files.length) {
|
|
1478
|
-
announce('
|
|
1485
|
+
announce('folders cannot be dropped - use new folder to create one'); return;
|
|
1479
1486
|
}
|
|
1480
1487
|
uploadFiles(files);
|
|
1481
1488
|
},
|
|
@@ -1964,11 +1971,11 @@ function chatMain() {
|
|
|
1964
1971
|
children: 'This agent\'s CLI was not found on the server. Pick another agent or install it.' }));
|
|
1965
1972
|
}
|
|
1966
1973
|
if (state.confirmingNewChat) {
|
|
1967
|
-
banners.push(Alert({ key: 'confnew', kind: 'warn', title: 'Clear
|
|
1974
|
+
banners.push(Alert({ key: 'confnew', kind: 'warn', title: 'Clear conversation?',
|
|
1968
1975
|
children: [
|
|
1969
1976
|
h('span', { key: 'cntxt' }, 'This cannot be undone. '),
|
|
1970
1977
|
Btn({ key: 'cnno', onClick: () => { clearTimeout(_newChatArmTimer); state.confirmingNewChat = false; render(); }, children: 'cancel' }),
|
|
1971
|
-
Btn({ key: 'cnyes', danger: true, onClick: confirmNewChat, children: 'yes, clear
|
|
1978
|
+
Btn({ key: 'cnyes', danger: true, onClick: confirmNewChat, children: 'yes, clear conversation' })] }));
|
|
1972
1979
|
}
|
|
1973
1980
|
if (state.cwdError) {
|
|
1974
1981
|
banners.push(Alert({ key: 'cwderr', kind: 'warn', title: 'Invalid working directory', children: state.cwdError }));
|
|
@@ -1998,7 +2005,7 @@ function chatMain() {
|
|
|
1998
2005
|
Btn({ key: 'agretry', onClick: () => loadAgents(), children: 'retry' })] }));
|
|
1999
2006
|
}
|
|
2000
2007
|
if (state.chat.loadingTranscript) {
|
|
2001
|
-
banners.push(Alert({ key: 'transcriptload', kind: 'info', title: 'Loading prior conversation
|
|
2008
|
+
banners.push(Alert({ key: 'transcriptload', kind: 'info', title: 'Loading prior conversation…',
|
|
2002
2009
|
children: [Spinner({ key: 'trspin', size: 'sm' })] }));
|
|
2003
2010
|
}
|
|
2004
2011
|
if (state.chat.confirmingEdit) {
|
|
@@ -2012,7 +2019,7 @@ function chatMain() {
|
|
|
2012
2019
|
const lastMsg = state.chat.messages.length ? state.chat.messages[state.chat.messages.length - 1] : null;
|
|
2013
2020
|
const lastErr = lastMsg ? lastMsg.error : null;
|
|
2014
2021
|
if (lastErr && !state.chat.busy) {
|
|
2015
|
-
banners.push(Alert({ key: 'chaterr', kind: 'error', title: '
|
|
2022
|
+
banners.push(Alert({ key: 'chaterr', kind: 'error', title: 'Message failed',
|
|
2016
2023
|
children: [
|
|
2017
2024
|
h('span', { key: 'cetxt', title: lastMsg.errorRaw || lastErr }, lastErr + ' '),
|
|
2018
2025
|
Btn({ key: 'ceretry', onClick: () => { delete lastMsg.error; delete lastMsg.errorRaw; retryLastTurn(); }, children: 'retry' }),
|
|
@@ -2959,7 +2966,7 @@ function resumeSidLabel(sid) {
|
|
|
2959
2966
|
const arr = Array.isArray(state.sessions) ? state.sessions : [];
|
|
2960
2967
|
const sess = arr.find((s) => s.sid === sid);
|
|
2961
2968
|
const label = sess && (projectLabel(sess.title) || projectLabel(sess.project));
|
|
2962
|
-
return label ||
|
|
2969
|
+
return label || 'untitled conversation';
|
|
2963
2970
|
}
|
|
2964
2971
|
|
|
2965
2972
|
function uniqueProjects() {
|
|
@@ -2985,7 +2992,7 @@ function runningPanel() {
|
|
|
2985
2992
|
children: [
|
|
2986
2993
|
// A discoverable path from "this running chat" to the management surface.
|
|
2987
2994
|
h('div', { key: 'runall', class: 'resume-banner', role: 'group' },
|
|
2988
|
-
h('span', { key: 'runalllbl', class: '
|
|
2995
|
+
h('span', { key: 'runalllbl', class: 't-meta' }, 'manage all running sessions'),
|
|
2989
2996
|
Btn({ key: 'runalllive', onClick: () => navTo('live'), children: 'view all in live' })),
|
|
2990
2997
|
...running.map((r) => {
|
|
2991
2998
|
const agentName = agentById(r.agentId)?.name || r.agentId || 'agent';
|
|
@@ -2995,7 +3002,7 @@ function runningPanel() {
|
|
|
2995
3002
|
// unkeyed one crashes webjsx applyDiff "reading 'key'").
|
|
2996
3003
|
return h('div', { key: 'run' + r.sessionId, class: 'resume-banner', role: 'group' },
|
|
2997
3004
|
h('span', { key: 'rd-' + r.sessionId, class: 'status-dot-disc ' + (isStopping ? 'status-dot-connecting' : 'status-dot-live'), 'aria-hidden': 'true' }),
|
|
2998
|
-
h('span', { key: 'rl-' + r.sessionId, class: '
|
|
3005
|
+
h('span', { key: 'rl-' + r.sessionId, class: 't-meta' }, agentName + (r.model ? ' · ' + r.model : '') + (elapsedMs ? ' · ' + fmtDuration(elapsedMs) : '') + (r.cwd ? ' · ' + pathBasename(r.cwd) : '')),
|
|
2999
3006
|
Btn({ key: 'open' + r.sessionId, onClick: () => navTo('live'), children: 'open in live' }),
|
|
3000
3007
|
Btn({ key: 'stop' + r.sessionId, disabled: isStopping, onClick: () => stopActiveChat(r.sessionId), children: isStopping ? 'stopping…' : 'stop' }));
|
|
3001
3008
|
}),
|
|
@@ -3451,6 +3458,11 @@ const debouncedSearch = debounce(runSearch, 300);
|
|
|
3451
3458
|
async function loadSession(sid, { focusEventI = null, focusEventTs = null, fromHash = false } = {}) {
|
|
3452
3459
|
// Guard against a bad sid from a malformed hash (e.g. "?sid=undefined").
|
|
3453
3460
|
if (!sid || sid === 'undefined' || sid === 'null') { state.selectedSid = null; render(); return; }
|
|
3461
|
+
if (sid === state.selectedSid && state.eventsLoaded && !fromHash && focusEventI == null && focusEventTs == null) {
|
|
3462
|
+
render();
|
|
3463
|
+
requestAnimationFrame(() => { document.querySelector('.app-side .row.active')?.scrollIntoView({ block: 'nearest' }); });
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3454
3466
|
state.selectedSid = sid;
|
|
3455
3467
|
state.events = [];
|
|
3456
3468
|
state.events._seen = new Set(); // O(1) dedupe by event index
|
|
@@ -441,7 +441,7 @@
|
|
|
441
441
|
--fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
|
|
442
442
|
--accent: var(--acid); --accent-fg: var(--ink); --accent-ink: var(--acid-deep);
|
|
443
443
|
/* A paper island under a dark ancestor must not inherit the dark signal pair. */
|
|
444
|
-
--flame: #C53E00; --amber: #
|
|
444
|
+
--flame: #C53E00; --amber: #7C570F; --warn: #E0241A; --sky: #3A6EFF;
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
/* thebird — warm-paper brand preset. A first-class swappable theme: it lives
|
|
@@ -664,7 +664,7 @@
|
|
|
664
664
|
.ds-247420 pre .k { color: var(--code-str-alt, var(--mascot)); }
|
|
665
665
|
.ds-247420 pre .s { color: var(--code-string, var(--green)); }
|
|
666
666
|
.ds-247420 pre .c { color: var(--fg-3); }
|
|
667
|
-
.ds-247420 pre .n { color: var(--
|
|
667
|
+
.ds-247420 pre .n { color: var(--code-num); }
|
|
668
668
|
|
|
669
669
|
/* ============================================================
|
|
670
670
|
AppShell — page frame. The topbar floats above a soft background;
|
|
@@ -850,10 +850,17 @@
|
|
|
850
850
|
font-weight: 600;
|
|
851
851
|
}
|
|
852
852
|
.ds-247420 .app-side .count {
|
|
853
|
-
background:
|
|
853
|
+
background: color-mix(in oklab, var(--fg) 10%, transparent);
|
|
854
|
+
color: var(--fg-2);
|
|
854
855
|
padding: 3px 10px; font-size: var(--fs-micro); font-weight: 700;
|
|
855
856
|
border-radius: var(--r-pill);
|
|
856
857
|
}
|
|
858
|
+
/* The lime active pill is the sidebar's one accent moment; its own count
|
|
859
|
+
chip rides the ink-on-accent pair instead of a second competing hue. */
|
|
860
|
+
.ds-247420 .app-side a.active .count {
|
|
861
|
+
background: color-mix(in oklab, var(--accent-fg) 82%, transparent);
|
|
862
|
+
color: var(--accent);
|
|
863
|
+
}
|
|
857
864
|
|
|
858
865
|
.ds-247420 .app-main {
|
|
859
866
|
padding: var(--space-5) var(--pad-x) 0;
|
|
@@ -966,15 +973,15 @@
|
|
|
966
973
|
an ink block with the lead as text, a confident two-tone flip. */
|
|
967
974
|
.ds-247420 .btn-primary {
|
|
968
975
|
background: var(--accent); color: var(--accent-fg);
|
|
969
|
-
font-weight: 700;
|
|
976
|
+
font-weight: 700;
|
|
970
977
|
}
|
|
971
978
|
.ds-247420 .btn-primary:hover { background: var(--fg); color: var(--accent-ink); transform: translateY(-1px); box-shadow: var(--shadow-2); }
|
|
972
979
|
.ds-247420 .btn-ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 2px var(--fg); }
|
|
973
980
|
.ds-247420 .btn-ghost:hover { background: var(--fg); color: var(--bg); transform: translateY(-1px); }
|
|
974
981
|
.ds-247420 .btn:active, .ds-247420 .btn-primary:active, .ds-247420 .btn-ghost:active { transform: translateY(1px); box-shadow: none; }
|
|
975
982
|
.ds-247420 .btn:focus-visible, .ds-247420 .btn-primary:focus-visible, .ds-247420 .btn-ghost:focus-visible, .ds-247420 .ds-icon-btn:focus-visible {
|
|
976
|
-
outline:
|
|
977
|
-
outline-offset:
|
|
983
|
+
outline: var(--focus-w) solid var(--focus-color);
|
|
984
|
+
outline-offset: var(--focus-offset);
|
|
978
985
|
}
|
|
979
986
|
|
|
980
987
|
/* ============================================================
|
|
@@ -993,12 +1000,12 @@
|
|
|
993
1000
|
.ds-247420 .ds-icon-btn-lg { width: 40px; height: 40px; }
|
|
994
1001
|
.ds-247420 .ds-icon-btn-xl { width: 48px; height: 48px; }
|
|
995
1002
|
.ds-247420 .ds-icon-btn-ghost { background: transparent; }
|
|
996
|
-
.ds-247420 .ds-icon-btn-ghost:hover { background: var(--bg
|
|
1003
|
+
.ds-247420 .ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
|
|
997
1004
|
.ds-247420 .ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
|
|
998
1005
|
.ds-247420 .ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
|
|
999
1006
|
/* warn = destructive ACTION tone; flame stays exclusively error STATUS. */
|
|
1000
1007
|
.ds-247420 .ds-icon-btn-danger { background: var(--warn); color: var(--on-color); }
|
|
1001
|
-
.ds-247420 .ds-icon-btn-danger:hover { filter: brightness(
|
|
1008
|
+
.ds-247420 .ds-icon-btn-danger:hover { filter: brightness(0.92); }
|
|
1002
1009
|
.ds-247420 .ds-icon-btn:active { transform: translateY(1px); }
|
|
1003
1010
|
.ds-247420 .ds-icon-btn:disabled, .ds-247420 .ds-icon-btn.is-disabled {
|
|
1004
1011
|
opacity: 0.5; cursor: not-allowed; pointer-events: none;
|
|
@@ -1148,7 +1155,7 @@
|
|
|
1148
1155
|
white-space: pre-wrap;
|
|
1149
1156
|
font-family: var(--ff-mono);
|
|
1150
1157
|
font-size: var(--fs-sm);
|
|
1151
|
-
line-height: var(--lh-snug
|
|
1158
|
+
line-height: var(--lh-snug);
|
|
1152
1159
|
margin-top: 8px;
|
|
1153
1160
|
padding: 10px 12px;
|
|
1154
1161
|
background: var(--bg);
|
|
@@ -1204,7 +1211,7 @@
|
|
|
1204
1211
|
.ds-247420 .row.row-nocode { grid-template-columns: minmax(0, 1fr) auto; }
|
|
1205
1212
|
|
|
1206
1213
|
.ds-247420 .row .code { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
|
|
1207
|
-
.ds-247420 .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug
|
|
1214
|
+
.ds-247420 .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
|
|
1208
1215
|
.ds-247420 .row .title .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
|
|
1209
1216
|
/* App typescale: list rows are quiet working chrome (the 18px/600 default is a
|
|
1210
1217
|
marketing-surface voice). One size for ALL app list rows - matches
|
|
@@ -1227,15 +1234,45 @@
|
|
|
1227
1234
|
No centered stack. */
|
|
1228
1235
|
.ds-247420 .ds-hero {
|
|
1229
1236
|
padding: var(--space-9) 0 var(--space-8);
|
|
1230
|
-
display: grid; gap: var(--space-5) var(--space-
|
|
1237
|
+
display: grid; gap: var(--space-5) var(--space-5);
|
|
1231
1238
|
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
|
|
1232
|
-
grid-template-areas: 'title title' 'body
|
|
1233
|
-
align-items:
|
|
1239
|
+
grid-template-areas: 'title title' 'body aside';
|
|
1240
|
+
align-items: start;
|
|
1234
1241
|
max-width: var(--measure-wide);
|
|
1235
1242
|
}
|
|
1236
1243
|
.ds-247420 .ds-hero-head { grid-area: title; display: grid; gap: var(--space-3); }
|
|
1237
1244
|
.ds-247420 .ds-hero-body { grid-area: body; }
|
|
1238
|
-
|
|
1245
|
+
/* The right column carries its own visual weight — a spined, halftone-
|
|
1246
|
+
textured card holding the badge/stat cluster and the CTAs — so the
|
|
1247
|
+
asymmetric grid reads as a deliberate composition, not leftover space
|
|
1248
|
+
beside the narrow body copy. Stretches to the body column's height. */
|
|
1249
|
+
.ds-247420 .ds-hero-aside {
|
|
1250
|
+
grid-area: aside; position: relative; isolation: isolate;
|
|
1251
|
+
align-self: stretch; display: flex; flex-direction: column;
|
|
1252
|
+
justify-content: space-between; gap: var(--space-5);
|
|
1253
|
+
background: var(--bg-2);
|
|
1254
|
+
border-radius: 0 var(--r-2) var(--r-2) 0;
|
|
1255
|
+
padding: var(--space-5) var(--space-5) var(--space-5) calc(var(--space-4) + var(--bw-chunk));
|
|
1256
|
+
}
|
|
1257
|
+
.ds-247420 .ds-hero-aside::before {
|
|
1258
|
+
content: ''; position: absolute; left: 0; top: 0; bottom: 0;
|
|
1259
|
+
width: var(--bw-chunk); background: var(--accent);
|
|
1260
|
+
border-radius: var(--bw-chunk) 0 0 var(--bw-chunk);
|
|
1261
|
+
}
|
|
1262
|
+
.ds-247420 .ds-hero-aside::after {
|
|
1263
|
+
content: ''; position: absolute; inset: 0; z-index: -1;
|
|
1264
|
+
pointer-events: none;
|
|
1265
|
+
background-image: radial-gradient(currentColor 1px, transparent 1.2px);
|
|
1266
|
+
background-size: var(--halftone-size) var(--halftone-size);
|
|
1267
|
+
opacity: 0.1; border-radius: inherit;
|
|
1268
|
+
}
|
|
1269
|
+
.ds-247420 .ds-hero-stats { display: flex; flex-direction: column; gap: var(--space-2); }
|
|
1270
|
+
.ds-247420 .ds-hero-stat {
|
|
1271
|
+
font-family: var(--ff-mono); font-size: var(--fs-sm);
|
|
1272
|
+
color: var(--fg-2); letter-spacing: var(--tr-tight);
|
|
1273
|
+
padding-bottom: var(--space-2); border-bottom: var(--bw-hair) solid var(--bg-3);
|
|
1274
|
+
}
|
|
1275
|
+
.ds-247420 .ds-hero-stat:last-child { border-bottom: 0; padding-bottom: 0; }
|
|
1239
1276
|
.ds-247420 .ds-hero-title {
|
|
1240
1277
|
font-family: var(--ff-display); font-weight: 700;
|
|
1241
1278
|
font-size: clamp(40px, 9cqi, 116px);
|
|
@@ -1249,17 +1286,26 @@
|
|
|
1249
1286
|
}
|
|
1250
1287
|
/* The lead phrase in the title — printed in the electric lead, not glowing. */
|
|
1251
1288
|
.ds-247420 .ds-hero-accent { color: var(--accent-ink); font-weight: 700; }
|
|
1252
|
-
.ds-247420 .ds-hero-actions {
|
|
1289
|
+
.ds-247420 .ds-hero-actions {
|
|
1290
|
+
display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
|
|
1291
|
+
align-self: start; margin-top: var(--space-hair, 4px);
|
|
1292
|
+
}
|
|
1253
1293
|
/* Container-queried (the whole shell is; a 500px pane on a wide viewport
|
|
1254
1294
|
would keep the two-column grid under a width @media). Left-aligned stack —
|
|
1255
1295
|
no centering — preserving the asymmetric intent. */
|
|
1256
1296
|
@container (max-width: 900px) {
|
|
1257
1297
|
.ds-247420 .ds-hero {
|
|
1258
1298
|
grid-template-columns: minmax(0, 1fr);
|
|
1259
|
-
grid-template-areas: 'title' 'body' '
|
|
1299
|
+
grid-template-areas: 'title' 'body' 'aside';
|
|
1260
1300
|
align-items: start;
|
|
1261
1301
|
padding: var(--space-7) 0 var(--space-6);
|
|
1262
1302
|
}
|
|
1303
|
+
.ds-247420 .ds-hero-aside {
|
|
1304
|
+
border-radius: var(--r-2); flex-direction: row; flex-wrap: wrap;
|
|
1305
|
+
justify-content: flex-start; align-items: center;
|
|
1306
|
+
}
|
|
1307
|
+
.ds-247420 .ds-hero-stats { flex-direction: row; flex-wrap: wrap; }
|
|
1308
|
+
.ds-247420 .ds-hero-stat { border-bottom: 0; padding-bottom: 0; }
|
|
1263
1309
|
}
|
|
1264
1310
|
.ds-247420 .ds-chat-title { margin: 0; font-size: inherit; }
|
|
1265
1311
|
|
|
@@ -2434,6 +2480,7 @@
|
|
|
2434
2480
|
border-color: var(--warn);
|
|
2435
2481
|
color: var(--on-color);
|
|
2436
2482
|
}
|
|
2483
|
+
.ds-247420 .btn-primary.danger:hover { filter: brightness(0.92); border-color: var(--warn); }
|
|
2437
2484
|
|
|
2438
2485
|
/* -- Preview ------------------------------------------------ */
|
|
2439
2486
|
.ds-247420 .ds-preview-head {
|
|
@@ -3081,7 +3128,6 @@
|
|
|
3081
3128
|
monospace count chips.
|
|
3082
3129
|
============================================================ */
|
|
3083
3130
|
.ds-247420 .app-side .count {
|
|
3084
|
-
background: color-mix(in oklab, var(--mascot) 92%, transparent);
|
|
3085
3131
|
padding: 1px 8px; font-size: var(--fs-micro); font-weight: 700;
|
|
3086
3132
|
font-family: var(--ff-mono); letter-spacing: 0.04em;
|
|
3087
3133
|
min-width: 18px; text-align: center;
|
|
@@ -3236,6 +3282,14 @@
|
|
|
3236
3282
|
transform var(--dur-snap) var(--ease);
|
|
3237
3283
|
}
|
|
3238
3284
|
|
|
3285
|
+
/* Native checkbox/radio tint — browser default is UA blue, which fights the
|
|
3286
|
+
single lime lead accent wherever a raw control lands outside a bespoke
|
|
3287
|
+
toggle (e.g. signin's "remember me"). accent-color re-tints the native
|
|
3288
|
+
control box without hand-drawing a replacement. */
|
|
3289
|
+
.ds-247420 input[type="checkbox"], .ds-247420 input[type="radio"] {
|
|
3290
|
+
accent-color: var(--accent-ink);
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3239
3293
|
/* Prevent double-tap zoom on buttons (iOS) */
|
|
3240
3294
|
.ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost, .ds-247420 button {
|
|
3241
3295
|
-webkit-user-select: none;
|
|
@@ -3903,6 +3957,10 @@
|
|
|
3903
3957
|
@container (max-width: 900px) {
|
|
3904
3958
|
.ds-247420 .app-side-toggle { display: inline-flex; }
|
|
3905
3959
|
.ds-247420 .app-topbar .brand { margin-left: 44px; }
|
|
3960
|
+
/* Merged-chrome layout (.app-chrome > .app-crumb) puts the breadcrumb, not
|
|
3961
|
+
the topbar brand, at the left edge where the absolute-positioned toggle
|
|
3962
|
+
sits — without this the crumb text renders directly under the button. */
|
|
3963
|
+
.ds-247420 .app-chrome > .app-crumb { margin-left: 44px; }
|
|
3906
3964
|
}
|
|
3907
3965
|
|
|
3908
3966
|
/* Desktop: the app shell is exactly viewport-height and contains its own
|
|
@@ -4697,6 +4755,31 @@
|
|
|
4697
4755
|
@media (max-width: 480px) {
|
|
4698
4756
|
.ds-247420 .ds-home-panel { margin: var(--space-1, 4px) 0; }
|
|
4699
4757
|
}
|
|
4758
|
+
/* Home landing section tablist (site/theme.mjs Tabs()) — bare .tabs had no
|
|
4759
|
+
rule anywhere, so the four links rendered as unstyled inline text jammed
|
|
4760
|
+
together with no separation. Mirror the topbar nav pill-tab treatment. */
|
|
4761
|
+
.ds-247420 .tabs[role="tablist"] {
|
|
4762
|
+
display: flex;
|
|
4763
|
+
flex-wrap: wrap;
|
|
4764
|
+
gap: var(--space-1, 4px);
|
|
4765
|
+
font-size: var(--fs-sm);
|
|
4766
|
+
}
|
|
4767
|
+
.ds-247420 .tabs[role="tablist"] a {
|
|
4768
|
+
display: flex;
|
|
4769
|
+
align-items: center;
|
|
4770
|
+
gap: var(--space-1, 4px);
|
|
4771
|
+
padding: var(--space-2, 8px) var(--space-3, 12px);
|
|
4772
|
+
border-radius: var(--r-pill);
|
|
4773
|
+
color: var(--fg-2);
|
|
4774
|
+
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
4775
|
+
}
|
|
4776
|
+
.ds-247420 .tabs[role="tablist"] a:hover { background: var(--bg-2); color: var(--fg); }
|
|
4777
|
+
.ds-247420 .tabs[role="tablist"] a.active {
|
|
4778
|
+
color: var(--accent-ink);
|
|
4779
|
+
background: color-mix(in oklab, var(--accent) 16%, transparent);
|
|
4780
|
+
box-shadow: inset 0 -2px 0 0 var(--accent);
|
|
4781
|
+
font-weight: 600;
|
|
4782
|
+
}
|
|
4700
4783
|
.ds-247420 .ds-quickstart {
|
|
4701
4784
|
padding: var(--space-3, 16px) var(--space-4, 22px);
|
|
4702
4785
|
display: flex;
|
|
@@ -5188,9 +5271,9 @@
|
|
|
5188
5271
|
}
|
|
5189
5272
|
|
|
5190
5273
|
.ds-247420 .cm-channel-item.voice-active {
|
|
5191
|
-
color: var(--green
|
|
5274
|
+
color: var(--green);
|
|
5192
5275
|
}
|
|
5193
|
-
.ds-247420 .cm-channel-item.voice-active .cm-ch-icon { color: var(--green
|
|
5276
|
+
.ds-247420 .cm-channel-item.voice-active .cm-ch-icon { color: var(--green); }
|
|
5194
5277
|
.ds-247420 .cm-channel-item.voice-active:hover {
|
|
5195
5278
|
background: color-mix(in oklab, var(--green) 12%, transparent);
|
|
5196
5279
|
}
|
|
@@ -5236,7 +5319,7 @@
|
|
|
5236
5319
|
}
|
|
5237
5320
|
|
|
5238
5321
|
.ds-247420 .cm-ch-icon.voice-active-badge {
|
|
5239
|
-
color: var(--green
|
|
5322
|
+
color: var(--green);
|
|
5240
5323
|
text-shadow: 0 0 8px var(--green-2);
|
|
5241
5324
|
}
|
|
5242
5325
|
|
|
@@ -5343,7 +5426,7 @@
|
|
|
5343
5426
|
color: var(--fg);
|
|
5344
5427
|
}
|
|
5345
5428
|
.ds-247420 .cm-ch-voice-user.speaking {
|
|
5346
|
-
color: var(--green
|
|
5429
|
+
color: var(--green);
|
|
5347
5430
|
}
|
|
5348
5431
|
.ds-247420 .cm-ch-voice-user.speaking .cm-ch-voice-user-avatar {
|
|
5349
5432
|
box-shadow: 0 0 0 2px var(--green-2);
|
|
@@ -5399,7 +5482,7 @@
|
|
|
5399
5482
|
font-size: var(--fs-micro);
|
|
5400
5483
|
text-transform: uppercase;
|
|
5401
5484
|
letter-spacing: var(--tr-caps);
|
|
5402
|
-
color: var(--green
|
|
5485
|
+
color: var(--green);
|
|
5403
5486
|
font-weight: 700;
|
|
5404
5487
|
display: inline-flex;
|
|
5405
5488
|
align-items: center;
|