agentgui 1.0.1031 → 1.0.1033

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.
@@ -92,7 +92,11 @@
92
92
  --accent-fg: var(--ink);
93
93
  --accent-ink: var(--acid-deep);
94
94
  --accent-bright: var(--acid); /* base value so var(--accent-bright) never falls back empty; ink + [data-accent] retune it */
95
- --accent-tint: color-mix(in oklab, var(--accent) 30%, var(--bg));
95
+ /* Blends --accent-ink (the readable/darker ink variant), not the raw
96
+ --accent fill, so light-theme active states clear contrast against --bg;
97
+ dark/ink and auto-dark restate the prior --accent-based value explicitly
98
+ below so this change does not leak into them via inheritance. */
99
+ --accent-tint: color-mix(in oklab, var(--accent-ink) 22%, var(--bg));
96
100
 
97
101
  /* On-color foregrounds — text/icons that sit ON a saturated fill (accent,
98
102
  danger, category chips). Theme-driven so white-on-color never hard-codes
@@ -329,6 +333,9 @@
329
333
  --accent-fg: var(--ink);
330
334
  --accent-ink: var(--acid); /* on ink, the lime itself reads as bright text */
331
335
  --accent-bright: var(--acid);
336
+ /* Preserves the prior --accent-based blend for dark; the :root light-theme
337
+ value above was retuned to blend --accent-ink instead. */
338
+ --accent-tint: color-mix(in oklab, var(--accent) 30%, var(--bg));
332
339
  --danger: oklch(0.68 0.19 25);
333
340
  --flame: #FF5A1F;
334
341
  --amber: #D9A93A;
@@ -343,6 +350,14 @@
343
350
  --code-num: var(--sun);
344
351
  }
345
352
 
353
+ /* Restores the pre-existing (weaker) dark-theme selection tint after the
354
+ light-theme-only bump in app-shell.css's base ::selection rule. */
355
+ .ds-247420[data-theme="ink"] ::selection,
356
+ .ds-247420[data-theme="dark"] ::selection {
357
+ background: color-mix(in oklab, var(--accent) 24%, var(--bg-2));
358
+ color: var(--fg);
359
+ }
360
+
346
361
  /* NOTE: the [data-theme="auto"] block below mirrors the
347
362
  [data-theme="ink"/"dark"] block above token-for-token. 'auto + OS-dark' and
348
363
  'explicit dark' are the same visual context and resolve every token —
@@ -370,6 +385,7 @@
370
385
  --accent-fg: var(--ink);
371
386
  --accent-ink: var(--acid);
372
387
  --accent-bright: var(--acid);
388
+ --accent-tint: color-mix(in oklab, var(--accent) 30%, var(--bg));
373
389
  --danger: oklch(0.68 0.19 25);
374
390
  --flame: #FF5A1F;
375
391
  --amber: #D9A93A;
@@ -381,6 +397,10 @@
381
397
  --code-str-alt: var(--mascot);
382
398
  --code-num: var(--sun);
383
399
  }
400
+ .ds-247420[data-theme="auto"] ::selection {
401
+ background: color-mix(in oklab, var(--accent) 24%, var(--bg-2));
402
+ color: var(--fg);
403
+ }
384
404
  }
385
405
 
386
406
  /* Nested-scope safety: if .ds-247420 appears under another .ds-247420 (e.g.
@@ -440,6 +460,7 @@
440
460
  --bg: var(--paper); --bg-2: var(--paper-2); --bg-3: var(--paper-3);
441
461
  --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
442
462
  --accent: var(--acid); --accent-fg: var(--ink); --accent-ink: var(--acid-deep);
463
+ --accent-tint: color-mix(in oklab, var(--accent-ink) 22%, var(--bg));
443
464
  /* A paper island under a dark ancestor must not inherit the dark signal pair. */
444
465
  --flame: #C53E00; --amber: #7C570F; --warn: #E0241A; --sky: #3A6EFF;
445
466
  }
@@ -546,8 +567,8 @@
546
567
  }
547
568
  .ds-247420 .skip-link:focus {
548
569
  top: 10px;
549
- outline: 2px solid var(--accent-ink);
550
- outline-offset: 2px;
570
+ outline: var(--focus-w) solid var(--focus-color);
571
+ outline-offset: var(--focus-offset);
551
572
  }
552
573
  .ds-247420 body {
553
574
  background: var(--bg);
@@ -558,7 +579,12 @@
558
579
  -webkit-font-smoothing: antialiased;
559
580
  text-rendering: optimizeLegibility;
560
581
  }
561
- .ds-247420 ::selection { background: color-mix(in oklab, var(--accent) 24%, var(--bg-2)); color: var(--fg); }
582
+ /* Light (paper, the default theme) needs a stronger accent share than dark to
583
+ clear a visible selection tint against --bg-2 -- the dark-theme value (24%)
584
+ read too weak on paper. Dark/ink keeps its existing 24% mix, restored below
585
+ in the ink/dark + auto-dark blocks (mirrors the --danger/--flame pattern of
586
+ scoping a value per theme rather than sharing one across both). */
587
+ .ds-247420 ::selection { background: color-mix(in oklab, var(--accent) 46%, var(--bg-2)); color: var(--fg); }
562
588
 
563
589
  /* Every root has a CQ container so fluid type can resolve to a meaningful inline-size. */
564
590
  .ds-247420 .app, .ds-247420 .ds-stage {
@@ -763,8 +789,8 @@
763
789
  }
764
790
  .ds-247420 .app-topbar nav a:hover { background: var(--bg-2); color: var(--fg); }
765
791
  .ds-247420 .app-topbar nav a:focus-visible {
766
- outline: 2px solid var(--accent-ink);
767
- outline-offset: 2px;
792
+ outline: var(--focus-w) solid var(--focus-color);
793
+ outline-offset: var(--focus-offset);
768
794
  }
769
795
  /* Active tab reads as a subtle tinted pill with an accent underline rather than
770
796
  an oversized filled oval that sits taller than its inactive siblings and reads
@@ -799,8 +825,8 @@
799
825
  width: 100%;
800
826
  }
801
827
  .ds-247420 .app-search:focus-within {
802
- outline: 2px solid var(--accent-ink);
803
- outline-offset: 2px;
828
+ outline: var(--focus-w) solid var(--focus-color);
829
+ outline-offset: var(--focus-offset);
804
830
  }
805
831
 
806
832
  .ds-247420 .app-crumb {
@@ -841,8 +867,8 @@
841
867
  }
842
868
  .ds-247420 .app-side a:hover { background: var(--bg-2); color: var(--fg); }
843
869
  .ds-247420 .app-side a:focus-visible {
844
- outline: 2px solid var(--accent-ink);
845
- outline-offset: 2px;
870
+ outline: var(--focus-w) solid var(--focus-color);
871
+ outline-offset: var(--focus-offset);
846
872
  }
847
873
  .ds-247420 .app-side a.active {
848
874
  color: var(--accent-fg);
@@ -943,6 +969,19 @@
943
969
  .ds-247420 .app-status .item:last-of-type:not(:only-of-type) { display: none; }
944
970
  }
945
971
 
972
+ /* The "dateline" — ASCII bar used at the top of every preview/brand page.
973
+ 3-4 flex slots; a .spread filler pushes the trailing slot to the far
974
+ edge instead of every span running together with no gap. */
975
+ .ds-247420 .dateline {
976
+ display: flex; align-items: center; gap: var(--space-3);
977
+ flex-wrap: nowrap; overflow: hidden;
978
+ font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.2;
979
+ letter-spacing: 0.02em;
980
+ color: var(--fg-3);
981
+ }
982
+ .ds-247420 .dateline span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
983
+ .ds-247420 .dateline .spread { flex: 1 1 auto; min-width: var(--space-3); }
984
+
946
985
  /* ============================================================
947
986
  Primitives
948
987
  ============================================================ */
@@ -1002,7 +1041,7 @@
1002
1041
  .ds-247420 .ds-icon-btn-ghost { background: transparent; }
1003
1042
  .ds-247420 .ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
1004
1043
  .ds-247420 .ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
1005
- .ds-247420 .ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
1044
+ .ds-247420 .ds-icon-btn-primary:hover { background: var(--fg); color: var(--accent-ink); }
1006
1045
  /* warn = destructive ACTION tone; flame stays exclusively error STATUS. */
1007
1046
  .ds-247420 .ds-icon-btn-danger { background: var(--warn); color: var(--on-color); }
1008
1047
  .ds-247420 .ds-icon-btn-danger:hover { filter: brightness(0.92); }
@@ -1021,19 +1060,27 @@
1021
1060
  border-radius: var(--r-pill);
1022
1061
  background: var(--bg-3); color: var(--fg-2);
1023
1062
  }
1024
- .ds-247420 .ds-badge.tone-green { background: var(--green-tint); color: var(--green-deep); }
1063
+ /* Canonical tone names are tone-success / tone-error / tone-neutral. Every
1064
+ other tone name grouped into the same rule below (tone-green/tone-live,
1065
+ tone-flame, tone-wip, tone-sun/tone-yellow, tone-ok/tone-miss) is a
1066
+ true-synonym legacy alias, kept working but sharing one declaration so the
1067
+ tone-family colors can't drift apart across names. */
1068
+ .ds-247420 .ds-badge.tone-green, .ds-247420 .ds-badge.tone-live, .ds-247420 .ds-badge.tone-success {
1069
+ background: var(--green-tint); color: var(--green-deep);
1070
+ }
1071
+ .ds-247420 .ds-badge.tone-flame, .ds-247420 .ds-badge.tone-error {
1072
+ background: var(--flame); color: var(--on-color);
1073
+ }
1074
+ .ds-247420 .ds-badge.tone-wip, .ds-247420 .ds-badge.tone-neutral {
1075
+ background: var(--bg-3); color: var(--fg-2);
1076
+ }
1025
1077
  .ds-247420 .ds-badge.tone-purple { background: var(--purple-tint); color: var(--purple-deep); }
1026
1078
  .ds-247420 .ds-badge.tone-mascot { background: var(--mascot-tint); color: var(--ink); }
1027
- .ds-247420 .ds-badge.tone-sun { background: var(--sun); color: var(--ink); }
1028
- .ds-247420 .ds-badge.tone-flame { background: var(--flame); color: var(--on-color); }
1029
- .ds-247420 .ds-badge.tone-live { background: var(--green-tint); color: var(--green-deep); }
1030
- .ds-247420 .ds-badge.tone-wip { background: var(--bg-3); color: var(--fg-2); }
1031
- .ds-247420 .ds-badge.tone-error { background: var(--flame); color: var(--on-color); }
1032
- .ds-247420 .ds-badge.tone-success { background: var(--green-tint); color: var(--green-deep); }
1033
- .ds-247420 .ds-badge.tone-neutral { background: var(--bg-3); color: var(--fg-2); }
1079
+ .ds-247420 .ds-badge.tone-sun, .ds-247420 .ds-badge.tone-yellow {
1080
+ background: var(--sun); color: var(--ink);
1081
+ }
1034
1082
  .ds-247420 .ds-badge.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
1035
1083
  .ds-247420 .ds-badge.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
1036
- .ds-247420 .ds-badge.tone-yellow { background: var(--sun); color: var(--ink); }
1037
1084
 
1038
1085
  .ds-247420 .chip {
1039
1086
  display: inline-flex; align-items: center; gap: 6px;
@@ -1044,19 +1091,22 @@
1044
1091
  letter-spacing: var(--tr-caps); text-transform: uppercase;
1045
1092
  border-radius: var(--r-pill);
1046
1093
  }
1047
- .ds-247420 .chip.tone-green { background: var(--green-tint); color: var(--green-deep); }
1094
+ /* Same canonical/legacy-alias grouping as .ds-badge above. */
1095
+ .ds-247420 .chip.tone-green, .ds-247420 .chip.tone-live, .ds-247420 .chip.tone-success, .ds-247420 .chip.tone-ok {
1096
+ background: var(--green-tint); color: var(--green-deep);
1097
+ }
1098
+ .ds-247420 .chip.tone-flame, .ds-247420 .chip.tone-error, .ds-247420 .chip.tone-miss {
1099
+ background: var(--flame); color: var(--on-color);
1100
+ }
1101
+ .ds-247420 .chip.tone-wip, .ds-247420 .chip.tone-neutral {
1102
+ background: var(--bg-3); color: var(--fg-2);
1103
+ }
1048
1104
  .ds-247420 .chip.tone-purple { background: var(--purple-tint); color: var(--purple-deep); }
1049
1105
  .ds-247420 .chip.tone-mascot { background: var(--mascot-tint); color: var(--ink); }
1050
- .ds-247420 .chip.tone-sun { background: var(--sun); color: var(--ink); }
1051
- .ds-247420 .chip.tone-flame { background: var(--flame); color: var(--on-color); }
1052
- .ds-247420 .chip.tone-live { background: var(--green-tint); color: var(--green-deep); }
1053
- .ds-247420 .chip.tone-wip { background: var(--bg-3); color: var(--fg-2); }
1054
- .ds-247420 .chip.tone-error { background: var(--flame); color: var(--on-color); }
1055
- .ds-247420 .chip.tone-success { background: var(--green-tint); color: var(--green-deep); }
1106
+ .ds-247420 .chip.tone-sun, .ds-247420 .chip.tone-yellow {
1107
+ background: var(--sun); color: var(--ink);
1108
+ }
1056
1109
  .ds-247420 .chip.tone-disabled { background: var(--bg-3); color: var(--fg-3); }
1057
- .ds-247420 .chip.tone-ok { background: var(--green-tint); color: var(--green-deep); }
1058
- .ds-247420 .chip.tone-miss { background: var(--flame); color: var(--on-color); }
1059
- .ds-247420 .chip.tone-neutral { background: var(--bg-3); color: var(--fg-2); }
1060
1110
  .ds-247420 .chip.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
1061
1111
  .ds-247420 .chip.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
1062
1112
  .ds-247420 .chip.tone-yellow { background: var(--sun); color: var(--ink); }
@@ -1088,13 +1138,22 @@
1088
1138
  background: var(--panel-1, var(--bg-2));
1089
1139
  border: var(--bw-hair) solid var(--rule);
1090
1140
  border-radius: var(--r-2);
1091
- margin: 0 0 var(--space-5);
1141
+ margin: 0 0 var(--space-4);
1092
1142
  padding: var(--space-3);
1093
1143
  position: relative;
1094
1144
  /* Crisp, restrained elevation — a hairline border does the edge definition;
1095
1145
  the shadow only adds a whisper of lift, not a soft glow-card float. */
1096
1146
  box-shadow: var(--shadow-1);
1097
- transition: box-shadow var(--dur-base) var(--ease), border-color var(--dur-snap) var(--ease);
1147
+ transition: box-shadow var(--dur-base) var(--ease-spring), border-color var(--dur-snap) var(--ease),
1148
+ transform var(--dur-base) var(--ease-spring);
1149
+ }
1150
+ /* Vercel-style card lift: any panel sitting inside a density grid (trio/grid)
1151
+ gets a restrained hover escalation — the standalone/full-width panel stays
1152
+ flat so page chrome doesn't jitter on scroll-adjacent hover. */
1153
+ .ds-247420 .ds-panel-trio > .panel:hover, .ds-247420 .ds-panel-grid > .panel:hover {
1154
+ box-shadow: var(--shadow-2);
1155
+ border-color: var(--rule-strong);
1156
+ transform: translateY(-2px);
1098
1157
  }
1099
1158
  /* Editorial accent spine — an opt-in printed-ink rule down the left edge that
1100
1159
  reads as a magazine pull-quote bar, not a glow card. */
@@ -1146,9 +1205,16 @@
1146
1205
  /* Only background + the leading rail animate; padding/size never change on
1147
1206
  interaction, so they are deliberately absent (a padding transition here was
1148
1207
  dead and misleading). */
1149
- transition: background var(--dur-snap) var(--ease);
1208
+ transition: background var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring);
1150
1209
  }
1151
1210
  .ds-247420 .row + .row { margin-top: 2px; }
1211
+ /* Interactive rows (anchor/button wrappers) get a hairline lift on hover,
1212
+ matching the btn/panel elevation language — non-interactive rows (plain
1213
+ divs used as static list items) are unaffected since the selector needs a
1214
+ real interactive role. */
1215
+ .ds-247420 a.row:hover, .ds-247420 button.row:hover, .ds-247420 .row[role="button"]:hover {
1216
+ box-shadow: var(--shadow-1);
1217
+ }
1152
1218
  /* `detail` drops to its own full-width line. The row is a grid, so span every
1153
1219
  track (grid-column 1/-1); flex-basis:100% covers the flex-row fallback. */
1154
1220
  .ds-247420 .ds-row-detail {
@@ -1220,6 +1286,9 @@
1220
1286
  .ds-247420[data-typescale="app"] .row { padding: 12px 16px; }
1221
1287
  .ds-247420[data-typescale="app"] .row .title { font-size: var(--fs-sm); font-weight: 500; }
1222
1288
  .ds-247420 .row .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
1289
+ /* Context-pane cwd fact reads as a path (like .ds-dash-cwd/.ds-session-agent/
1290
+ .ds-dash-model) -- scoped to that one row so no other Row .sub is affected. */
1291
+ .ds-247420 .ds-context-cwd-row .row .sub { font-family: var(--ff-mono); }
1223
1292
  .ds-247420 .row .meta { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; align-self: center; }
1224
1293
  /* WorksList meta pairs a label with a disclosure chevron, inline-aligned. */
1225
1294
  .ds-247420 .ds-works-meta { display: inline-flex; align-items: center; gap: .4em; }
@@ -1239,6 +1308,17 @@
1239
1308
  grid-template-areas: 'title title' 'body aside';
1240
1309
  align-items: start;
1241
1310
  max-width: var(--measure-wide);
1311
+ position: relative; isolation: isolate;
1312
+ }
1313
+ /* Restrained depth wash, not a marketing glow-gradient: a single very-low-
1314
+ opacity accent-ink radial anchored top-right, sitting under the grain/
1315
+ halftone texture (z-index -1, same isolation trick as .ds-hero-aside::after)
1316
+ so it reads as ambient light rather than a colored blob. Token-only. */
1317
+ .ds-247420 .ds-hero::before {
1318
+ content: ''; position: absolute; z-index: -1;
1319
+ top: -10%; right: -10%; width: 60%; height: 140%;
1320
+ background: radial-gradient(closest-side, color-mix(in oklab, var(--accent-ink) 10%, transparent), transparent 70%);
1321
+ pointer-events: none;
1242
1322
  }
1243
1323
  .ds-247420 .ds-hero-head { grid-area: title; display: grid; gap: var(--space-3); }
1244
1324
  .ds-247420 .ds-hero-body { grid-area: body; }
@@ -1477,7 +1557,7 @@
1477
1557
  .ds-247420 table tr.clickable { cursor: pointer; }
1478
1558
  .ds-247420 table tr.clickable:hover td { background: var(--bg-2); }
1479
1559
  .ds-247420 table tr.clickable:focus-visible {
1480
- outline: 2px solid var(--accent-ink);
1560
+ outline: var(--focus-w) solid var(--focus-color);
1481
1561
  outline-offset: -2px;
1482
1562
  }
1483
1563
  .ds-247420 table tr.clickable:focus-visible td { background: var(--bg-2); }
@@ -1655,6 +1735,10 @@
1655
1735
  flex: 1 1 100%; margin-left: 0; order: 3; min-width: 0; max-width: 100%;
1656
1736
  display: flex; gap: 2px; flex-wrap: nowrap;
1657
1737
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
1738
+ /* Fade the trailing edge so a clipped last item (e.g. "source ->" cut to
1739
+ "sour") reads as scrollable content, not a broken/truncated label. */
1740
+ mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1741
+ -webkit-mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1658
1742
  }
1659
1743
  .ds-247420 .app-topbar nav::-webkit-scrollbar { display: none; }
1660
1744
  .ds-247420 .app-topbar nav a {
@@ -1708,8 +1792,12 @@
1708
1792
  font-size: var(--fs-xs);
1709
1793
  }
1710
1794
  .ds-247420 .ds-file-open { gap: 10px; }
1711
- /* On mobile, fold meta under the title and keep actions inline. */
1712
- .ds-247420 .ds-file-row .ds-file-meta { font-size: var(--fs-micro); }
1795
+ /* At mobile row widths, a fixed-size meta column (date/size) plus the
1796
+ always-visible action buttons leave the flexible title only a few px —
1797
+ not enough for even one legible character before the two collide. Drop
1798
+ the metadata column here; the title + actions still fully identify and
1799
+ operate on the row, and meta stays available in the file viewer. */
1800
+ .ds-247420 .ds-file-row .ds-file-meta { display: none; }
1713
1801
  .ds-247420 .ds-file-row .ds-file-actions { opacity: 1; }
1714
1802
  /* H4: floor finger-sized controls so file actions/sort/filter/breadcrumb are
1715
1803
  reachable by touch (cohesion sweep). */
@@ -1910,7 +1998,7 @@
1910
1998
  flex-direction: column;
1911
1999
  gap: 4px;
1912
2000
  }
1913
- .ds-247420 .ds-file-grid:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-2); }
2001
+ .ds-247420 .ds-file-grid:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); border-radius: var(--r-2); }
1914
2002
 
1915
2003
  /* Listing wrapper holds the optional filter + sort header above the grid. */
1916
2004
  .ds-247420 .ds-file-listing { display: flex; flex-direction: column; gap: var(--space-2); min-height: 0; }
@@ -1932,7 +2020,7 @@
1932
2020
  }
1933
2021
  .ds-247420 .ds-file-sort-btn:hover { color: var(--fg-2); background: var(--bg-2); }
1934
2022
  .ds-247420 .ds-file-sort-btn.active { color: var(--accent-ink); }
1935
- .ds-247420 .ds-file-sort-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2023
+ .ds-247420 .ds-file-sort-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
1936
2024
 
1937
2025
  /* Skeleton shimmer rows shown while a directory loads. */
1938
2026
  .ds-247420 .ds-file-row-skeleton { cursor: default; pointer-events: none; }
@@ -1980,7 +2068,7 @@
1980
2068
  color: inherit; font: inherit; text-align: left; cursor: pointer;
1981
2069
  }
1982
2070
  .ds-247420 .ds-file-open[disabled] { cursor: default; }
1983
- .ds-247420 .ds-file-open:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-1); }
2071
+ .ds-247420 .ds-file-open:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); border-radius: var(--r-1); }
1984
2072
  .ds-247420 .ds-file-row:hover {
1985
2073
  background: var(--bg-2);
1986
2074
  border-color: var(--rule);
@@ -2011,6 +2099,12 @@
2011
2099
  .ds-247420 .ds-file-row .ds-file-meta {
2012
2100
  font-family: var(--ff-mono); font-size: var(--fs-xs);
2013
2101
  color: var(--fg-3); white-space: nowrap;
2102
+ /* Never shrink below content: a flex sibling with white-space:nowrap and
2103
+ the default flex-shrink:1 silently overflows its own box (no ellipsis)
2104
+ when the row runs out of width, painting the date/size over the title
2105
+ and action icons at mobile widths. Fixed-size the meta column instead
2106
+ and let .title (flex:1, min-width:0, ellipsis) absorb the squeeze. */
2107
+ flex-shrink: 0;
2014
2108
  }
2015
2109
 
2016
2110
  /* File icon — glyph chip, tinted per type. */
@@ -2078,7 +2172,7 @@
2078
2172
  }
2079
2173
  .ds-247420 .ds-file-check:hover { background: var(--bg-3); color: var(--fg); }
2080
2174
  .ds-247420 .ds-file-check.is-marked { color: var(--accent-ink); }
2081
- .ds-247420 .ds-file-check:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2175
+ .ds-247420 .ds-file-check:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2082
2176
  .ds-247420 .ds-file-check[disabled] { opacity: 0.4; cursor: default; }
2083
2177
  .ds-247420 .ds-file-row.is-marked { background: var(--accent-tint); border-color: var(--accent); }
2084
2178
  .ds-247420 .ds-file-selectall {
@@ -2088,7 +2182,7 @@
2088
2182
  padding: var(--space-1); border-radius: var(--r-1);
2089
2183
  }
2090
2184
  .ds-247420 .ds-file-selectall:hover { background: var(--bg-2); color: var(--fg); }
2091
- .ds-247420 .ds-file-selectall:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2185
+ .ds-247420 .ds-file-selectall:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2092
2186
  .ds-247420 .ds-file-controls { display: flex; align-items: center; gap: var(--space-2); padding: 0 var(--space-2) var(--space-1); flex-wrap: wrap; }
2093
2187
  .ds-247420 .ds-file-controls .spread { flex: 1 1 auto; }
2094
2188
  .ds-247420 .ds-file-controls .ds-file-sort { padding: 0; }
@@ -2126,7 +2220,7 @@
2126
2220
  }
2127
2221
  .ds-247420 .ds-density-btn:hover { color: var(--fg); }
2128
2222
  .ds-247420 .ds-density-btn.active { background: var(--accent-tint); color: var(--fg); }
2129
- .ds-247420 .ds-density-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2223
+ .ds-247420 .ds-density-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2130
2224
 
2131
2225
  /* Compact density — tighter rows for long listings. */
2132
2226
  .ds-247420 .ds-file-grid[data-density="compact"] { gap: 2px; }
@@ -2164,7 +2258,7 @@
2164
2258
  background: none; border: none; cursor: pointer; color: var(--fg);
2165
2259
  }
2166
2260
  .ds-247420 .ds-file-cell-open[disabled] { cursor: default; }
2167
- .ds-247420 .ds-file-cell-open:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; border-radius: var(--r-2); }
2261
+ .ds-247420 .ds-file-cell-open:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; border-radius: var(--r-2); }
2168
2262
  .ds-247420 .ds-file-cell-media {
2169
2263
  display: flex; align-items: center; justify-content: center;
2170
2264
  width: 100%; aspect-ratio: 4 / 3;
@@ -2369,6 +2463,19 @@
2369
2463
  background: var(--accent); border-radius: var(--r-pill);
2370
2464
  transition: width var(--dur-base) var(--ease);
2371
2465
  }
2466
+ /* Indeterminate: percent is unknown mid-transfer (fetch gives no chunk-level
2467
+ progress) — a sliding marquee bar reads as "working", not stuck at 0%. */
2468
+ .ds-247420 .ds-upload-bar.indeterminate .ds-upload-fill {
2469
+ width: 40%; transition: none;
2470
+ animation: ds-upload-marquee 1.1s ease-in-out infinite;
2471
+ }
2472
+ @keyframes ds-upload-marquee {
2473
+ 0% { transform: translateX(-100%); }
2474
+ 100% { transform: translateX(250%); }
2475
+ }
2476
+ @media (prefers-reduced-motion: reduce) {
2477
+ .ds-247420 .ds-upload-bar.indeterminate .ds-upload-fill { animation: none; width: 100%; opacity: 0.5; }
2478
+ }
2372
2479
  .ds-247420 .ds-upload-pct {
2373
2480
  font-family: var(--ff-mono); font-size: var(--fs-micro);
2374
2481
  color: var(--fg-3); text-align: right;
@@ -2391,7 +2498,7 @@
2391
2498
  color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-micro);
2392
2499
  }
2393
2500
  .ds-247420 .ds-upload-act:hover { background: var(--bg-3); color: var(--fg); }
2394
- .ds-247420 .ds-upload-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2501
+ .ds-247420 .ds-upload-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2395
2502
  @media (hover: none), (pointer: coarse) {
2396
2503
  .ds-247420 .ds-upload-act { min-height: 44px; min-width: 44px; }
2397
2504
  /* 44px floor for file controls on ANY touch device, not only narrow ones
@@ -2462,7 +2569,7 @@
2462
2569
  border-radius: var(--r-2); color: var(--fg);
2463
2570
  font-family: inherit; font-size: var(--fs-sm);
2464
2571
  }
2465
- .ds-247420 .ds-modal-input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
2572
+ .ds-247420 .ds-modal-input:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2466
2573
  /* iOS auto-zooms inputs under 16px on focus, breaking the modal layout. */
2467
2574
  @media (hover: none), (pointer: coarse) {
2468
2575
  .ds-247420 .ds-modal-input { font-size: 16px; min-height: 44px; }
@@ -2649,7 +2756,7 @@
2649
2756
  transition: color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
2650
2757
  }
2651
2758
  .ds-247420 .ds-segmented .ds-seg-btn:hover { color: var(--fg); }
2652
- .ds-247420 .ds-segmented .ds-seg-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2759
+ .ds-247420 .ds-segmented .ds-seg-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2653
2760
  .ds-247420 .ds-segmented .ds-seg-btn.is-on {
2654
2761
  background: var(--bg); color: var(--fg);
2655
2762
  box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule);
@@ -3095,12 +3202,12 @@
3095
3202
  transition: background var(--dur-snap, .15s) var(--ease, ease), color var(--dur-snap, .15s) var(--ease, ease);
3096
3203
  }
3097
3204
  .ds-247420 .composer-btn:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); color: var(--fg); }
3098
- .ds-247420 .chat-composer .send:hover { filter: brightness(1.08); }
3205
+ .ds-247420 .chat-composer .send:hover { filter: brightness(0.92); }
3099
3206
  .ds-247420 .chat-composer .send:active { filter: brightness(0.94); }
3100
3207
  .ds-247420 .chat-composer .send:focus-visible,
3101
3208
  .ds-247420 .composer-btn:focus-visible {
3102
- outline: 2px solid var(--accent-ink);
3103
- outline-offset: 2px;
3209
+ outline: var(--focus-w) solid var(--focus-color);
3210
+ outline-offset: var(--focus-offset);
3104
3211
  }
3105
3212
  .ds-247420 .chat-composer .send:disabled {
3106
3213
  background: var(--bg-3); color: var(--fg-3); cursor: not-allowed; transform: none;
@@ -3453,6 +3560,86 @@
3453
3560
  color: var(--fg-3);
3454
3561
  }
3455
3562
 
3563
+ /* Long-form reading voice — quiet sans, generous line-height, capped to a
3564
+ readable measure so a wide viewport never stretches body copy edge to
3565
+ edge. Links use --accent-ink (never the bare fill, which is unreadable
3566
+ as text). */
3567
+ .ds-247420 .prose {
3568
+ max-width: var(--measure);
3569
+ font-family: var(--ff-body); font-size: var(--fs-body); line-height: 1.6;
3570
+ color: var(--fg);
3571
+ }
3572
+ .ds-247420 .prose p { margin: 0 0 var(--space-4) 0; }
3573
+ .ds-247420 .prose p:last-child { margin-bottom: 0; }
3574
+ .ds-247420 .prose a { color: var(--accent-ink); text-decoration-color: var(--rule-strong); text-underline-offset: 0.15em; }
3575
+ .ds-247420 .prose a:hover { text-decoration-color: currentColor; }
3576
+
3577
+ /* Rubber-stamp motif — a bordered, uppercase, letter-spaced badge with a
3578
+ slight built-in rotation (variants may override via inline transform for
3579
+ a stronger tilt). Max 1 per page per the component's own caption. */
3580
+ .ds-247420 .stamp {
3581
+ display: inline-block;
3582
+ font-family: var(--ff-mono); font-size: var(--fs-xs); font-weight: 700;
3583
+ text-transform: uppercase; letter-spacing: 0.08em;
3584
+ padding: var(--space-1-5, var(--space-2)) var(--space-3);
3585
+ border: 2px solid var(--fg);
3586
+ border-radius: var(--r-hair);
3587
+ color: var(--fg);
3588
+ transform: rotate(-2deg);
3589
+ white-space: nowrap;
3590
+ }
3591
+ .ds-247420 .stamp.ink { background: var(--ink); border-color: var(--ink); color: var(--paper); }
3592
+ .ds-247420 .stamp.acid { background: var(--accent); border-color: var(--accent-ink); color: var(--accent-ink); }
3593
+ .ds-247420 .stamp.purple { border-color: var(--purple-2); color: var(--purple-2); }
3594
+ .ds-247420 .stamp.mascot { border-color: var(--mascot); color: var(--mascot-deep); }
3595
+
3596
+ /* Same rubber-stamp face, but a real interactive <button> — resets UA button
3597
+ chrome so it isn't blue link text in a browser default box. */
3598
+ .ds-247420 .btn-stamp {
3599
+ display: inline-block; cursor: pointer;
3600
+ font-family: var(--ff-mono); font-size: var(--fs-xs); font-weight: 700;
3601
+ text-transform: uppercase; letter-spacing: 0.08em;
3602
+ padding: var(--space-1-5, var(--space-2)) var(--space-3);
3603
+ border: 2px solid var(--fg);
3604
+ border-radius: var(--r-hair);
3605
+ background: transparent; color: var(--fg);
3606
+ transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
3607
+ }
3608
+ .ds-247420 .btn-stamp:hover { background: var(--panel-hover); }
3609
+ .ds-247420 .btn-stamp.acid { border-color: var(--accent-ink); color: var(--accent-ink); }
3610
+ .ds-247420 .btn-stamp.acid:hover { background: var(--accent-tint); }
3611
+ .ds-247420 .btn-stamp.purple { border-color: var(--purple-2); color: var(--purple-2); }
3612
+ .ds-247420 .btn-stamp.mascot { border-color: var(--mascot); color: var(--mascot-deep); }
3613
+
3614
+ /* Structural hairlines — "no boxes, no cards, structure comes from rules."
3615
+ Three weights: .rule (default separator), .rule-double (major section
3616
+ break), .rule-dotted (optional/skippable). Applied to a bare <hr>, which
3617
+ otherwise falls back to the browser's default inset groove line. */
3618
+ .ds-247420 hr.rule, .ds-247420 hr.rule-double, .ds-247420 hr.rule-dotted {
3619
+ width: 100%; height: 0; border: 0;
3620
+ }
3621
+ .ds-247420 hr.rule { border-top: 1px solid var(--rule); }
3622
+ .ds-247420 hr.rule-double { border-top: 3px double var(--rule-strong); }
3623
+ .ds-247420 hr.rule-dotted { border-top: 1px dotted var(--rule-strong); }
3624
+
3625
+ /* Hairline-only text input — no box, no fill. A single bottom rule that
3626
+ thickens to 2px on focus, matching the row/rule zero-border aesthetic
3627
+ instead of a browser-default boxed field. */
3628
+ .ds-247420 .input {
3629
+ display: block; width: 100%; box-sizing: border-box;
3630
+ border: 0; border-bottom: 1px solid var(--rule-strong);
3631
+ border-radius: var(--r-0);
3632
+ background: transparent;
3633
+ padding: var(--space-2) var(--space-1);
3634
+ font: inherit; color: var(--fg);
3635
+ }
3636
+ .ds-247420 .input::placeholder { color: var(--fg-3); }
3637
+ .ds-247420 .input:focus-visible {
3638
+ outline: none;
3639
+ border-bottom-width: 2px;
3640
+ border-bottom-color: var(--accent-ink);
3641
+ }
3642
+
3456
3643
  /* -- Field controls: themed base for TextField / Select / SearchInput --
3457
3644
  Root fix: previously only `transition` was set, so themed apps got
3458
3645
  browser-default white boxes in dark mode and labels collided with inputs
@@ -3553,8 +3740,8 @@
3553
3740
 
3554
3741
  /* Base focus-visible: 2px ring + 2px offset clears dark bg-3 surfaces (WCAG 1.4.11) */
3555
3742
  .ds-247420 :focus-visible {
3556
- outline: 2px solid var(--accent-ink);
3557
- outline-offset: 2px;
3743
+ outline: var(--focus-w) solid var(--focus-color);
3744
+ outline-offset: var(--focus-offset);
3558
3745
  }
3559
3746
 
3560
3747
  /* Enhanced focus-visible for all interactive elements */
@@ -3563,8 +3750,8 @@
3563
3750
  .ds-247420[role="tab"]:focus-visible,
3564
3751
  .ds-247420 .row:focus-visible,
3565
3752
  .ds-247420 .row[tabindex]:focus-visible {
3566
- outline: 2px solid var(--accent-ink);
3567
- outline-offset: 2px;
3753
+ outline: var(--focus-w) solid var(--focus-color);
3754
+ outline-offset: var(--focus-offset);
3568
3755
  }
3569
3756
 
3570
3757
  /* Skip to main content link */
@@ -3953,7 +4140,7 @@
3953
4140
  border-radius: var(--r-1, 6px);
3954
4141
  cursor: pointer;
3955
4142
  }
3956
- .ds-247420 .app-side-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4143
+ .ds-247420 .app-side-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
3957
4144
  @container (max-width: 900px) {
3958
4145
  .ds-247420 .app-side-toggle { display: inline-flex; }
3959
4146
  .ds-247420 .app-topbar .brand { margin-left: 44px; }
@@ -4047,7 +4234,7 @@
4047
4234
  .ds-247420 .ws-resizer { grid-row: 1 / -1; align-self: stretch; justify-self: end; width: 8px; margin-right: -4px; z-index: 5; cursor: col-resize; background: transparent; border: none; padding: 0; touch-action: none; }
4048
4235
  .ds-247420 .ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background: transparent; transition: background var(--dur-snap) var(--ease); }
4049
4236
  .ds-247420 .ws-resizer:hover::after, .ds-247420 .ws-resizer:focus-visible::after { background: var(--accent); }
4050
- .ds-247420 .ws-resizer:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
4237
+ .ds-247420 .ws-resizer:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
4051
4238
  .ds-247420 .ws-resizer.ws-resizer-rail { grid-column: 1; }
4052
4239
  .ds-247420 .ws-resizer.ws-resizer-sessions { grid-column: 2; }
4053
4240
  .ds-247420 .ws-resizer.ws-resizer-pane { grid-column: 3; justify-self: end; }
@@ -4099,7 +4286,7 @@
4099
4286
  border-radius: var(--r-1); cursor: pointer;
4100
4287
  }
4101
4288
  .ds-247420 .ws-rail-toggle:hover { background: var(--bg-3); color: var(--fg); }
4102
- .ds-247420 .ws-rail-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4289
+ .ds-247420 .ws-rail-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4103
4290
  .ds-247420 .ws-rail-inner { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: var(--space-3) var(--space-2); gap: var(--space-2); }
4104
4291
  .ds-247420 .ws-rail-head { display: flex; align-items: center; min-height: 36px; padding: 0 var(--space-2); }
4105
4292
  .ds-247420 .ws-rail-brand { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-body); color: var(--fg); white-space: nowrap; overflow: hidden; }
@@ -4111,8 +4298,8 @@
4111
4298
  font-family: var(--ff-body); font-size: var(--fs-sm); font-weight: 600;
4112
4299
  min-height: 40px; white-space: nowrap; overflow: hidden;
4113
4300
  }
4114
- .ds-247420 .ws-rail-action:hover { filter: brightness(1.08); }
4115
- .ds-247420 .ws-rail-action:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4301
+ .ds-247420 .ws-rail-action:hover { filter: brightness(0.92); }
4302
+ .ds-247420 .ws-rail-action:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4116
4303
  .ds-247420 .ws-rail-nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
4117
4304
  .ds-247420 .ws-rail-item {
4118
4305
  display: flex; align-items: center; gap: var(--space-2);
@@ -4122,7 +4309,7 @@
4122
4309
  font-family: var(--ff-body); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden;
4123
4310
  }
4124
4311
  .ds-247420 .ws-rail-item:hover { background: var(--bg-3); color: var(--fg); }
4125
- .ds-247420 .ws-rail-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
4312
+ .ds-247420 .ws-rail-item:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
4126
4313
  .ds-247420 .ws-rail-item.active { background: var(--accent-tint); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
4127
4314
  .ds-247420 .ws-rail-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
4128
4315
  .ds-247420 .ws-rail-item-count { font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3); }
@@ -4195,7 +4382,7 @@
4195
4382
  /* Desktop-only chrome toggle (sessions collapse): inverse of the mobile drawer-toggle. */
4196
4383
  .ds-247420 .ws-desktop-toggle { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; background: none; color: var(--fg-2); cursor: pointer; border-radius: var(--r-1); }
4197
4384
  .ds-247420 .ws-desktop-toggle:hover { background: var(--bg-2); color: var(--fg); }
4198
- .ds-247420 .ws-desktop-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4385
+ .ds-247420 .ws-desktop-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4199
4386
  @media (max-width: 900px) { .ds-247420 .ws-desktop-toggle { display: none; } }
4200
4387
  /* The pane collapse toggle is meaningless once the pane TRACK is dropped (the
4201
4388
  pane becomes a mobile overlay drawer at <=1480px, reached via its own
@@ -4319,7 +4506,7 @@
4319
4506
  .ds-247420 .ws-crumb .app-crumb .crumb-right { margin-left: 0; flex-wrap: wrap; min-width: 0; display: inline-flex; }
4320
4507
  }
4321
4508
  .ds-247420 .ws-drawer-toggle:hover { background: var(--bg-2); color: var(--fg); }
4322
- .ds-247420 .ws-drawer-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4509
+ .ds-247420 .ws-drawer-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4323
4510
 
4324
4511
  @media (prefers-reduced-motion: reduce) {
4325
4512
  .ds-247420 .ws-shell, .ds-247420 .ws-rail, .ds-247420 .ws-pane, .ds-247420 .ws-sessions, .ds-247420 .ws-scrim { transition: none; }
@@ -4344,7 +4531,7 @@
4344
4531
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
4345
4532
  }
4346
4533
  .ds-247420 .row-act:hover { background: var(--bg-3); color: var(--fg); }
4347
- .ds-247420 .row-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4534
+ .ds-247420 .row-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4348
4535
 
4349
4536
  /* FilterPills - a group of pill toggle buttons (aria-pressed). */
4350
4537
  .ds-247420 .ds-filter-pills { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@@ -4357,7 +4544,7 @@
4357
4544
  }
4358
4545
  .ds-247420 .ds-filter-pill:hover { background: var(--bg-3); color: var(--fg); }
4359
4546
  .ds-247420 .ds-filter-pill.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
4360
- .ds-247420 .ds-filter-pill:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4547
+ .ds-247420 .ds-filter-pill:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4361
4548
 
4362
4549
  /* Touch floor for the new small controls. */
4363
4550
  @media (pointer: coarse) {
@@ -4367,7 +4554,7 @@
4367
4554
  /* Disabled file actions (read-only row / in-flight mutation) stay visible but inert. */
4368
4555
  .ds-247420 .ds-file-act:disabled { opacity: .45; cursor: default; }
4369
4556
  .ds-247420 .ds-file-act:disabled:hover { background: transparent; color: var(--fg-3); }
4370
- .ds-247420 .ds-file-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4557
+ .ds-247420 .ds-file-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4371
4558
 
4372
4559
  /* ============================================================
4373
4560
  Print — linearize WorkspaceShell so main content prints in full.
@@ -4691,7 +4878,7 @@
4691
4878
  .ds-feature above), so the hover affordance is a lift, matching the same
4692
4879
  translateY + shadow idiom .chat-msg:hover .chat-bubble already uses. */
4693
4880
  .ds-247420 .ds-gallery-tile:hover { transform: translateY(-2px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 10%, transparent); }
4694
- .ds-247420 .ds-gallery-tile:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4881
+ .ds-247420 .ds-gallery-tile:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
4695
4882
  .ds-247420 .ds-gallery-tile--tight { min-height: clamp(96px, 14vw, 120px); }
4696
4883
  .ds-247420 .ds-lightbox {
4697
4884
  position: fixed; inset: 0; background: var(--scrim);
@@ -4771,9 +4958,10 @@
4771
4958
  padding: var(--space-2, 8px) var(--space-3, 12px);
4772
4959
  border-radius: var(--r-pill);
4773
4960
  color: var(--fg-2);
4774
- transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
4961
+ transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease),
4962
+ transform var(--dur-base) var(--ease-spring);
4775
4963
  }
4776
- .ds-247420 .tabs[role="tablist"] a:hover { background: var(--bg-2); color: var(--fg); }
4964
+ .ds-247420 .tabs[role="tablist"] a:hover { background: var(--bg-2); color: var(--fg); transform: translateY(-1px); }
4777
4965
  .ds-247420 .tabs[role="tablist"] a.active {
4778
4966
  color: var(--accent-ink);
4779
4967
  background: color-mix(in oklab, var(--accent) 16%, transparent);
@@ -5049,7 +5237,7 @@
5049
5237
  height: 48px;
5050
5238
  border-radius: var(--r-3);
5051
5239
  background: var(--bg-2);
5052
- color: var(--green-2);
5240
+ color: var(--green);
5053
5241
  display: flex;
5054
5242
  align-items: center;
5055
5243
  justify-content: center;
@@ -6654,6 +6842,7 @@
6654
6842
  flex-wrap: wrap;
6655
6843
  }
6656
6844
  .ds-247420 .agentchat-cwd-text {
6845
+ font-family: var(--ff-mono);
6657
6846
  overflow: hidden;
6658
6847
  text-overflow: ellipsis;
6659
6848
  white-space: nowrap;
@@ -6979,7 +7168,7 @@
6979
7168
  .ds-247420 .ds-session-title { font-size: var(--fs-sm); color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
6980
7169
  .ds-247420 .ds-session-sub { font-size: var(--fs-tiny); color: var(--fg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
6981
7170
  .ds-247420 .ds-session-meta { display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }
6982
- .ds-247420 .ds-session-agent { font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3); }
7171
+ .ds-247420 .ds-session-agent { font-size: var(--fs-tiny); color: var(--fg-3); }
6983
7172
  /* New-activity cue is a hollow accent RING so it stays shape-distinct from the
6984
7173
  running live disc (a solid pulsing accent dot) for colour-blind / reduced-motion users. */
6985
7174
  .ds-247420 .ds-session-unread { width: 8px; height: 8px; border-radius: 50%; background: transparent; box-shadow: inset 0 0 0 2px var(--accent); display: inline-block; }
@@ -7011,7 +7200,7 @@
7011
7200
  .ds-247420 .ds-dash-card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-2); }
7012
7201
  .ds-247420 .ds-dash-card.is-error { border-color: var(--flame); }
7013
7202
  .ds-247420 .ds-dash-card-head { display: flex; align-items: center; gap: var(--space-2); }
7014
- .ds-247420 .ds-dash-status { font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }
7203
+ .ds-247420 .ds-dash-status { font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: var(--tr-caps); }
7015
7204
  /* running tone unified on --accent (the later is-running rule + the live disc all
7016
7205
  use --accent); the dead var(--green) duplicate that lived here was removed. */
7017
7206
  .ds-247420 .ds-dash-status.is-error { color: var(--flame); }
@@ -7339,7 +7528,7 @@
7339
7528
  /* External (observed, not owned) session card: no stop control exists. */
7340
7529
  .ds-247420 .ds-dash-external {
7341
7530
  padding: 1px 6px; border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-pill);
7342
- font-size: var(--fs-micro); color: var(--fg-3); text-transform: uppercase; letter-spacing: .03em;
7531
+ font-size: var(--fs-micro); color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-caps);
7343
7532
  }
7344
7533
  .ds-247420 .ds-dash-card.is-external { border-style: dashed; }
7345
7534
 
@@ -7375,8 +7564,8 @@
7375
7564
  paragraph and the .them tint hugged text flush. Restore reading rhythm + give
7376
7565
  the tinted assistant row inner breathing room so it reads as a card. */
7377
7566
  .ds-247420 .chat-msg-flat .chat-role { margin-bottom: var(--space-2); }
7378
- .ds-247420 .chat-msg-flat .chat-md { line-height: 1.65; }
7379
- .ds-247420 .chat-msg-flat .chat-md p { margin: 8px 0; }
7567
+ .ds-247420 .chat-msg-flat .chat-md { line-height: var(--lh-long); }
7568
+ .ds-247420 .chat-msg-flat .chat-md p { margin: var(--space-2) 0; }
7380
7569
  .ds-247420 .chat-msg-flat.them { padding-block: calc(var(--space-3) * var(--density, 1) + 2px); }
7381
7570
  /* Inline backtick code (renderInline tags <code class=chat-tick>) - was a dead
7382
7571
  class relying on the generic .chat-bubble code rule, so notices / non-bubble
@@ -7431,7 +7620,7 @@
7431
7620
  .ds-247420 .chat-tool-label { color: var(--fg-3); font-size: var(--fs-tiny); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
7432
7621
  .ds-247420 .chat-tool-status {
7433
7622
  margin-left: auto; flex: 0 0 auto;
7434
- font-size: var(--fs-micro); font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
7623
+ font-size: var(--fs-micro); font-weight: 700; text-transform: uppercase; letter-spacing: var(--tr-caps);
7435
7624
  color: var(--fg-3);
7436
7625
  padding: 2px var(--space-2); border-radius: var(--r-pill);
7437
7626
  background: color-mix(in oklab, var(--fg) 6%, transparent);
@@ -7463,7 +7652,7 @@
7463
7652
  .ds-247420 .chat-code-lang {
7464
7653
  position: absolute; top: 0; left: 0; z-index: 2;
7465
7654
  padding: 2px var(--space-2); border-bottom-right-radius: var(--r-1);
7466
- font-family: var(--ff-mono); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .04em;
7655
+ font-family: var(--ff-mono); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tr-caps);
7467
7656
  color: var(--fg-3); background: color-mix(in oklab, var(--fg) 6%, transparent);
7468
7657
  pointer-events: none;
7469
7658
  }
@@ -7531,6 +7720,18 @@
7531
7720
  }
7532
7721
  @keyframes ds-skel-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
7533
7722
 
7723
+ /* Agent-picker list loading skeleton (shares the .ds-skel shimmer base above). */
7724
+ .ds-247420 .ds-agent-list-skeleton { display: flex; flex-direction: column; gap: var(--space-2); }
7725
+ .ds-247420 .ds-agent-row-skeleton { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
7726
+ .ds-247420 .ds-agent-row-skeleton .ds-skel { background: var(--bg-3); border-radius: var(--r-1); }
7727
+ .ds-247420 .ds-agent-row-skeleton .ds-skel-icon { height: 18px; width: 18px; flex: none; border-radius: var(--r-round, 50%); }
7728
+ .ds-247420 .ds-agent-row-skeleton .ds-skel-title { height: 12px; width: 40%; }
7729
+ .ds-247420 .ds-agent-row-skeleton .ds-skel-meta { height: 9px; width: 25%; margin-left: auto; }
7730
+ .ds-247420 .ds-agent-list-skeleton-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
7731
+ @media (prefers-reduced-motion: no-preference) {
7732
+ .ds-247420 .ds-agent-row-skeleton .ds-skel { animation: ds-skel-shimmer 1.3s ease-in-out infinite; background: linear-gradient(90deg, var(--bg-3) 0%, var(--bg-2) 50%, var(--bg-3) 100%); background-size: 200% 100%; }
7733
+ }
7734
+
7534
7735
  /* File code preview: paint Prism tokens (the bundle scoped them to the chat
7535
7736
  block only) + an optional non-selectable line-number gutter. */
7536
7737
  .ds-247420 .ds-preview-code code { color: var(--fg); }
@@ -8256,11 +8457,11 @@
8256
8457
  .ds-247420 .ds-ep-dialog-btn.kind-primary {
8257
8458
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
8258
8459
  }
8259
- .ds-247420 .ds-ep-dialog-btn.kind-primary:hover { filter: brightness(1.08); }
8460
+ .ds-247420 .ds-ep-dialog-btn.kind-primary:hover { filter: brightness(0.92); }
8260
8461
  .ds-247420 .ds-ep-dialog-btn.kind-danger {
8261
8462
  background: var(--danger); color: var(--on-accent); border-color: var(--danger);
8262
8463
  }
8263
- .ds-247420 .ds-ep-dialog-btn.kind-danger:hover { filter: brightness(1.1); }
8464
+ .ds-247420 .ds-ep-dialog-btn.kind-danger:hover { filter: brightness(0.92); }
8264
8465
 
8265
8466
  /* ---------------------------------------------------------------
8266
8467
  Toast
@@ -9261,7 +9462,8 @@
9261
9462
  border: var(--bw-hair, 1px) solid color-mix(in srgb, var(--fg) 12%, transparent);
9262
9463
  }
9263
9464
  .ds-247420 .health-summary.health-ok .health-chip:first-child {
9264
- color: var(--accent);
9465
+ color: var(--accent-ink);
9466
+ background: color-mix(in srgb, var(--accent) 16%, transparent);
9265
9467
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
9266
9468
  }
9267
9469
 
@@ -9284,13 +9486,14 @@
9284
9486
  .ds-247420 .cwd-bar-btn:hover { background: color-mix(in srgb, var(--fg) 14%, transparent); }
9285
9487
  .ds-247420 .cwd-bar-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
9286
9488
 
9287
- /* History no-session empty state: fill the void with a centered prompt. */
9489
+ /* History no-session empty state: natural height, no leftover void below. */
9288
9490
  .ds-247420 .history-empty {
9289
- display: flex; flex-direction: column; align-items: center; justify-content: center;
9290
- gap: .4em; text-align: center; min-height: 50vh; color: var(--fg-3);
9491
+ display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
9492
+ gap: .4em; text-align: center; padding: var(--space-6, 40px) 0 var(--space-4, 16px); color: var(--fg-3);
9291
9493
  }
9292
9494
  .ds-247420 .history-empty-title { margin: 0; font-size: var(--fs-lg); color: var(--fg-2); }
9293
9495
  .ds-247420 .history-empty-sub { margin: 0; max-width: 42ch; }
9496
+ .ds-247420 .history-empty-hints { margin: var(--space-5, 24px) auto 0; max-width: 46ch; text-align: left; }
9294
9497
 
9295
9498
  /* Settings: two-column on wide screens (backend + agents). Grid gap is the
9296
9499
  single source of rhythm between stacked Panels here - .panel's own