anentrypoint-design 0.0.210 → 0.0.211

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/app-shell.css CHANGED
@@ -590,8 +590,13 @@ body.canvas-host { background: transparent !important; }
590
590
  .row.rail-purple::before,
591
591
  .row.rail-flame::before { height: 56%; opacity: 1; }
592
592
  .row.rail-green::before { background: var(--accent); }
593
- .row.rail-purple::before { background: var(--purple-2, #7F18A4); }
593
+ .row.rail-purple::before { background: var(--purple-2); }
594
594
  .row.rail-flame::before { background: var(--flame); }
595
+ /* Differentiate the rail by SHAPE, not hue alone (color-blind safety): error
596
+ reads as a taller solid bar, subagent as a dashed/gapped fill, ok stays the
597
+ short solid bar. Paired with the sr-only status word emitted by Row(). */
598
+ .row.rail-flame::before { height: 64%; }
599
+ .row.rail-purple::before { background: repeating-linear-gradient(var(--purple-2) 0 4px, transparent 4px 7px); }
595
600
  .row-grid { /* explicit grid-template-columns set inline */ }
596
601
  /* A row with no leading code/index drops the empty first column so the title
597
602
  takes the full width instead of wrapping in the narrow code gutter. */
@@ -827,8 +832,8 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
827
832
  border: 0; border-radius: var(--r-2);
828
833
  box-shadow: inset 0 0 0 1px var(--rule);
829
834
  }
830
- .row-form input:focus,
831
- .row-form textarea:focus { box-shadow: inset 0 0 0 2px var(--accent); }
835
+ .row-form input:focus-visible,
836
+ .row-form textarea:focus-visible { box-shadow: var(--focus-ring-inset); }
832
837
 
833
838
  /* Field char counter (TextField maxLength) */
834
839
  .ds-field-count {
@@ -849,9 +854,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
849
854
  Responsive Design — Mobile (480px), Tablet (1024px), Desktop (1440px+)
850
855
  ============================================================ */
851
856
 
852
- /* ────────────────────────────────────────────────────────────────────
857
+ /* --------------------------------------------------------------------
853
858
  Mobile Portrait Breakpoint (480px and below)
854
- ────────────────────────────────────────────────────────────────────── */
859
+ ---------------------------------------------------------------------- */
855
860
  @media (max-width: 480px) {
856
861
  /* App Layout: single-column + drawer is handled once in the ≤900px block;
857
862
  no need to re-declare grid-template-columns here (was a redundant !important). */
@@ -975,9 +980,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
975
980
  .cli .copy { padding: 6px 12px; font-size: var(--fs-micro); }
976
981
  }
977
982
 
978
- /* ────────────────────────────────────────────────────────────────────
983
+ /* --------------------------------------------------------------------
979
984
  Container Query Responsive (720px and below)
980
- ────────────────────────────────────────────────────────────────────── */
985
+ ---------------------------------------------------------------------- */
981
986
  @container (max-width: 760px) {
982
987
  .app-body { grid-template-columns: 1fr !important; }
983
988
  .app-side-shell { border-right: 0; border-bottom: 1px solid var(--rule); }
@@ -987,9 +992,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
987
992
  .row .sub { grid-column: 1 / -1; order: 3; }
988
993
  }
989
994
 
990
- /* ────────────────────────────────────────────────────────────────────
995
+ /* --------------------------------------------------------------------
991
996
  Tablet Landscape Breakpoint (768px to 1024px)
992
- ────────────────────────────────────────────────────────────────────── */
997
+ ---------------------------------------------------------------------- */
993
998
  @media (min-width: 481px) and (max-width: 1024px) {
994
999
  /* App Layout — side handled by 900px drawer block; restore for 901-1024 */
995
1000
  .app-side a {
@@ -1066,9 +1071,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1066
1071
  }
1067
1072
  }
1068
1073
 
1069
- /* ────────────────────────────────────────────────────────────────────
1074
+ /* --------------------------------------------------------------------
1070
1075
  Mid Breakpoint (768px and below) — collapse sidebar + simplify row grid
1071
- ────────────────────────────────────────────────────────────────────── */
1076
+ ---------------------------------------------------------------------- */
1072
1077
  @media (max-width: 768px) {
1073
1078
  /* Sidebar stacks above main rather than sitting beside it */
1074
1079
  .app-body { grid-template-columns: 1fr; }
@@ -1083,9 +1088,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1083
1088
  .row .sub { grid-column: 1 / -1; }
1084
1089
  }
1085
1090
 
1086
- /* ────────────────────────────────────────────────────────────────────
1091
+ /* --------------------------------------------------------------------
1087
1092
  Desktop Breakpoint Enhancements (1025px and up)
1088
- ────────────────────────────────────────────────────────────────────── */
1093
+ ---------------------------------------------------------------------- */
1089
1094
  @media (min-width: 1025px) {
1090
1095
  /* Chat Bubbles */
1091
1096
  .chat-stack { max-width: min(70%, 480px); }
@@ -1106,7 +1111,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1106
1111
  .ds-chat-md { font-size: var(--fs-sm); line-height: 1.6; }
1107
1112
  .ds-chat-composer { display: flex; gap: 8px; padding: var(--space-4); }
1108
1113
  .ds-chat-composer input { flex: 1; padding: 13px 18px; background: var(--bg-2); border: 0; border-radius: var(--r-pill); font-family: inherit; font-size: var(--fs-sm); color: var(--fg); }
1109
- .ds-chat-composer input:focus { box-shadow: inset 0 0 0 2px var(--accent); }
1114
+ .ds-chat-composer input:focus-visible { box-shadow: var(--focus-ring-inset); }
1110
1115
 
1111
1116
  /* ============================================================
1112
1117
  File surface — responsive grid + row layouts
@@ -1132,7 +1137,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1132
1137
  background: var(--bg); color: var(--fg);
1133
1138
  border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
1134
1139
  }
1135
- .ds-file-filter-input:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
1140
+ .ds-file-filter-input:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }
1136
1141
  .ds-file-sort { display: flex; gap: var(--space-2); padding: 0 var(--space-2) var(--space-1); }
1137
1142
  .ds-file-sort-btn {
1138
1143
  font-size: var(--fs-tiny); font-family: var(--ff-mono); color: var(--fg-3);
@@ -1253,6 +1258,29 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1253
1258
  .ds-file-act-warn:hover { background: color-mix(in oklab, var(--warn) 18%, var(--bg)); color: var(--warn); }
1254
1259
 
1255
1260
  /* Multi-select — per-row checkbox, header tri-state, bulk action strip. */
1261
+ /* CSS-drawn multi-select checkbox: a bordered box that fills with the accent +
1262
+ a border-drawn tick when its parent button is .is-marked or aria-checked.
1263
+ Shared by FileRow/FileCell (.is-marked) and the file/session select-all +
1264
+ SessionCard select (aria-checked true/mixed) since the bundle concatenates
1265
+ all CSS. Replaces the old [x]/[ ] bracket text - no glyphs, AT keeps the
1266
+ role=checkbox/aria-checked name+state. */
1267
+ .ds-check-box {
1268
+ width: 15px; height: 15px; box-sizing: border-box; flex: 0 0 auto; position: relative;
1269
+ border: 1.5px solid var(--rule); border-radius: 4px;
1270
+ transition: background var(--dur-snap) var(--ease), border-color var(--dur-snap) var(--ease);
1271
+ }
1272
+ .is-marked > .ds-check-box,
1273
+ [aria-checked="true"] > .ds-check-box { background: var(--accent); border-color: var(--accent); }
1274
+ .is-marked > .ds-check-box::after,
1275
+ [aria-checked="true"] > .ds-check-box::after {
1276
+ content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
1277
+ border: solid var(--bg); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg);
1278
+ }
1279
+ [aria-checked="mixed"] > .ds-check-box { background: var(--accent); border-color: var(--accent); }
1280
+ [aria-checked="mixed"] > .ds-check-box::after {
1281
+ content: ""; position: absolute; left: 2px; right: 2px; top: 50%; height: 1.5px; margin-top: -0.75px; background: var(--bg);
1282
+ }
1283
+
1256
1284
  .ds-file-check {
1257
1285
  display: inline-flex; align-items: center; justify-content: center;
1258
1286
  min-width: 28px; height: 28px; padding: 0 4px;
@@ -1282,7 +1310,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1282
1310
  padding: var(--space-1) var(--space-2);
1283
1311
  background: var(--bg-2); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
1284
1312
  }
1285
- .ds-bulkbar-count { font-size: var(--fs-tiny); color: var(--fg-2); }
1313
+ .ds-bulkbar-count { font-size: var(--fs-sm); font-weight: 600; color: var(--fg-2); }
1286
1314
  /* BulkBar is a toolbar (it even declares role=toolbar): compact rect buttons,
1287
1315
  quiet destructive outline - the app arm-confirms destructive bulk actions
1288
1316
  via ConfirmDialog, so the strip never needs a loud CTA. */
@@ -1543,7 +1571,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1543
1571
  .ds-file-empty-glyph { font-size: 34px; opacity: 0.55; }
1544
1572
  .ds-file-empty-text { font-size: var(--fs-sm); }
1545
1573
 
1546
- /* ── Modals ───────────────────────────────────────────────── */
1574
+ /* -- Modals ------------------------------------------------- */
1547
1575
  .ds-modal-backdrop {
1548
1576
  position: fixed; inset: 0; z-index: var(--z-modal, 800);
1549
1577
  display: flex; align-items: center; justify-content: center;
@@ -1589,7 +1617,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1589
1617
  border-radius: var(--r-2); color: var(--fg);
1590
1618
  font-family: inherit; font-size: var(--fs-sm);
1591
1619
  }
1592
- .ds-modal-input:focus { outline: 2px solid var(--accent); outline-offset: 2px; }
1620
+ .ds-modal-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1593
1621
  /* In-body modal error (role=alert): mutation failures (409/403) surface INSIDE
1594
1622
  the dialog, not behind the fixed overlay. */
1595
1623
  .ds-modal-error {
@@ -1604,7 +1632,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1604
1632
  color: var(--on-color);
1605
1633
  }
1606
1634
 
1607
- /* ── Preview ──────────────────────────────────────────────── */
1635
+ /* -- Preview ------------------------------------------------ */
1608
1636
  .ds-preview-head {
1609
1637
  display: flex; align-items: center; gap: var(--space-3);
1610
1638
  padding: var(--space-3) var(--space-4);
@@ -1677,7 +1705,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1677
1705
  .ds-file-stage { padding: var(--space-3) var(--space-2); }
1678
1706
  }
1679
1707
 
1680
- /* ── File browser UX affordances ──────────────────────────── */
1708
+ /* -- File browser UX affordances ---------------------------- */
1681
1709
  /* Toolbar filter input — compact search box. */
1682
1710
  .ds-filter-input {
1683
1711
  width: clamp(120px, 22vw, 220px);
@@ -1686,7 +1714,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1686
1714
  border-radius: var(--r-pill); color: var(--fg);
1687
1715
  font-family: inherit; font-size: var(--fs-xs);
1688
1716
  }
1689
- .ds-filter-input:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
1717
+ .ds-filter-input:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }
1690
1718
 
1691
1719
  /* Loading skeleton — placeholder rows while a directory loads. */
1692
1720
  .ds-file-grid-loading { display: flex; flex-direction: column; gap: 4px; }
@@ -2209,7 +2237,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
2209
2237
  .app-side a .glyph { font-family: var(--ff-mono); font-size: 13px; font-weight: 600; color: var(--fg-3); text-align: center; }
2210
2238
  .app-side a.active .glyph { color: var(--accent); }
2211
2239
 
2212
- /* ── select primitive ─────────────────────────────────────────────────── */
2240
+ /* -- select primitive --------------------------------------------------- */
2213
2241
  .ds-select {
2214
2242
  width: 100%;
2215
2243
  min-width: 0;
@@ -2233,10 +2261,10 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
2233
2261
  background-repeat: no-repeat;
2234
2262
  cursor: pointer;
2235
2263
  }
2236
- .ds-select:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
2264
+ .ds-select:focus-visible { box-shadow: var(--focus-ring-inset); }
2237
2265
  .ds-select:hover { background-color: var(--bg-3); }
2238
2266
 
2239
- /* ── chat composer autogrow polish (sizing lives in the primary block) ── */
2267
+ /* -- chat composer autogrow polish (sizing lives in the primary block) -- */
2240
2268
  .chat-composer textarea {
2241
2269
  transition: height var(--dur-snap) var(--ease);
2242
2270
  }
@@ -2245,7 +2273,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
2245
2273
  cursor: not-allowed;
2246
2274
  }
2247
2275
 
2248
- /* ── mobile responsive: chat ──────────────────────────────────────────── */
2276
+ /* -- mobile responsive: chat -------------------------------------------- */
2249
2277
  @media (max-width: 768px) {
2250
2278
  .chat-stack { max-width: 100%; }
2251
2279
  .chat-msg { padding: 4px 0; }
@@ -2270,9 +2298,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
2270
2298
  Comprehensive improvements for perfect UX across all surfaces
2271
2299
  ============================================================ */
2272
2300
 
2273
- /* ────────────────────────────────────────────────────────────
2301
+ /* ------------------------------------------------------------
2274
2302
  Component States — Disabled, Loading, Error, Success
2275
- ────────────────────────────────────────────────────────────── */
2303
+ -------------------------------------------------------------- */
2276
2304
 
2277
2305
  /* Disabled state for all interactive elements */
2278
2306
  .btn:disabled, .btn-primary:disabled, .btn-ghost:disabled,
@@ -2324,9 +2352,9 @@ textarea.error {
2324
2352
  opacity: 0.8;
2325
2353
  }
2326
2354
 
2327
- /* ────────────────────────────────────────────────────────────
2355
+ /* ------------------------------------------------------------
2328
2356
  Enhanced Button Micro-Interactions
2329
- ────────────────────────────────────────────────────────────── */
2357
+ -------------------------------------------------------------- */
2330
2358
 
2331
2359
  /* Button scale feedback on active */
2332
2360
  .btn:active:not(:disabled),
@@ -2356,9 +2384,9 @@ input[type="checkbox"], input[type="radio"] {
2356
2384
  -webkit-touch-callout: none;
2357
2385
  }
2358
2386
 
2359
- /* ────────────────────────────────────────────────────────────
2387
+ /* ------------------------------------------------------------
2360
2388
  Drag-and-Drop Styles
2361
- ────────────────────────────────────────────────────────────── */
2389
+ -------------------------------------------------------------- */
2362
2390
 
2363
2391
  /* Draggable element */
2364
2392
  [draggable="true"], .draggable {
@@ -2415,9 +2443,9 @@ input[type="checkbox"], input[type="radio"] {
2415
2443
  50% { opacity: 1; }
2416
2444
  }
2417
2445
 
2418
- /* ────────────────────────────────────────────────────────────
2446
+ /* ------------------------------------------------------------
2419
2447
  Context Menu Styles
2420
- ────────────────────────────────────────────────────────────── */
2448
+ -------------------------------------------------------------- */
2421
2449
 
2422
2450
  .ds-context-menu {
2423
2451
  position: absolute;
@@ -2479,9 +2507,9 @@ input[type="checkbox"], input[type="radio"] {
2479
2507
  cursor: context-menu;
2480
2508
  }
2481
2509
 
2482
- /* ────────────────────────────────────────────────────────────
2510
+ /* ------------------------------------------------------------
2483
2511
  Enhanced Form Inputs
2484
- ────────────────────────────────────────────────────────────── */
2512
+ -------------------------------------------------------------- */
2485
2513
 
2486
2514
  input[type="text"],
2487
2515
  input[type="email"],
@@ -2507,7 +2535,7 @@ textarea::placeholder {
2507
2535
  color: var(--fg-3);
2508
2536
  }
2509
2537
 
2510
- /* ── Field controls: themed base for TextField / Select / SearchInput ──
2538
+ /* -- Field controls: themed base for TextField / Select / SearchInput --
2511
2539
  Root fix: previously only `transition` was set, so themed apps got
2512
2540
  browser-default white boxes in dark mode and labels collided with inputs
2513
2541
  because `.ds-field` had no layout. */
@@ -2556,7 +2584,7 @@ textarea::placeholder {
2556
2584
  .ds-field .ds-select:focus-visible,
2557
2585
  .ds-search-input:focus-visible {
2558
2586
  outline: none;
2559
- box-shadow: inset 0 0 0 2px var(--accent);
2587
+ box-shadow: var(--focus-ring-inset);
2560
2588
  }
2561
2589
  .ds-field input:disabled,
2562
2590
  .ds-field textarea:disabled,
@@ -2594,9 +2622,9 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2594
2622
  color: var(--fg);
2595
2623
  }
2596
2624
 
2597
- /* ────────────────────────────────────────────────────────────
2625
+ /* ------------------------------------------------------------
2598
2626
  Accessibility Enhancements
2599
- ────────────────────────────────────────────────────────────── */
2627
+ -------------------------------------------------------------- */
2600
2628
 
2601
2629
  /* Enhanced focus-visible for all interactive elements */
2602
2630
  [role="button"]:focus-visible,
@@ -2625,11 +2653,17 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2625
2653
  animation-iteration-count: 1 !important;
2626
2654
  transition-duration: 0.01ms !important;
2627
2655
  }
2656
+ /* Kill the residual paint frame of looping skeleton/shimmer placeholders and
2657
+ give reduced-motion users a steady placeholder fill instead. */
2658
+ .skeleton, .ds-skeleton, .ds-session-row-skeleton .ds-skel {
2659
+ animation: none !important;
2660
+ background: var(--bg-2) !important;
2661
+ }
2628
2662
  }
2629
2663
 
2630
- /* ────────────────────────────────────────────────────────────
2664
+ /* ------------------------------------------------------------
2631
2665
  Performance
2632
- ────────────────────────────────────────────────────────────── */
2666
+ -------------------------------------------------------------- */
2633
2667
 
2634
2668
  /* Limit layout/style containment to self-contained components. `paint` is
2635
2669
  intentionally omitted — it clips focus rings, tooltips and dropdowns that
@@ -2638,9 +2672,9 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2638
2672
  contain: layout style;
2639
2673
  }
2640
2674
 
2641
- /* ────────────────────────────────────────────────────────────
2675
+ /* ------------------------------------------------------------
2642
2676
  Mobile Touch Optimizations
2643
- ────────────────────────────────────────────────────────────── */
2677
+ -------------------------------------------------------------- */
2644
2678
 
2645
2679
  @media (hover: none) and (pointer: coarse) {
2646
2680
  /* Mobile devices: larger touch targets, faster responses */
@@ -2671,9 +2705,9 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2671
2705
  }
2672
2706
  }
2673
2707
 
2674
- /* ────────────────────────────────────────────────────────────
2708
+ /* ------------------------------------------------------------
2675
2709
  Theme Transition Smoothness
2676
- ────────────────────────────────────────────────────────────── */
2710
+ -------------------------------------------------------------- */
2677
2711
 
2678
2712
  /* Scoped to the DS wrapper so the design system never reaches out and
2679
2713
  animates the host document's html/body. */
@@ -2682,9 +2716,9 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2682
2716
  color var(--dur-base) var(--ease);
2683
2717
  }
2684
2718
 
2685
- /* ────────────────────────────────────────────────────────────
2719
+ /* ------------------------------------------------------------
2686
2720
  Empty State & Loading States
2687
- ────────────────────────────────────────────────────────────── */
2721
+ -------------------------------------------------------------- */
2688
2722
 
2689
2723
  .empty-state {
2690
2724
  display: flex; flex-direction: column; align-items: center; gap: var(--space-4);
@@ -2722,9 +2756,9 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
2722
2756
  .skeleton-line { height: 12px; margin-bottom: 12px; }
2723
2757
  .skeleton-title { height: 24px; margin-bottom: 16px; width: 60%; }
2724
2758
 
2725
- /* ────────────────────────────────────────────────────────────
2759
+ /* ------------------------------------------------------------
2726
2760
  Toast Notification Styles
2727
- ────────────────────────────────────────────────────────────── */
2761
+ -------------------------------------------------------------- */
2728
2762
 
2729
2763
  .toast {
2730
2764
  position: fixed;
@@ -3130,7 +3164,7 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
3130
3164
  /* Crumb band is the top chrome of the content column: a stable height so the
3131
3165
  top edge aligns with the rail head, and a left gutter matching .ws-main so
3132
3166
  the trail text is not flush against the rail border. */
3133
- .ws-crumb { flex: 0 0 auto; min-height: 48px; padding: 0 var(--space-4); display: flex; align-items: center; gap: var(--space-1); border-bottom: var(--bw-hair) solid var(--bg-3); }
3167
+ .ws-crumb { flex: 0 0 auto; min-height: 48px; padding: 0 var(--space-5); display: flex; align-items: center; gap: var(--space-1); border-bottom: var(--bw-hair) solid var(--bg-3); }
3134
3168
  .ws-crumb-main { flex: 1 1 auto; min-width: 0; }
3135
3169
  /* Content column gutter. Claude-Code-class calm: file grid / dashboard / event
3136
3170
  list / history get a generous, consistent inner gutter instead of butting
package/chat.css CHANGED
@@ -177,14 +177,14 @@
177
177
  }
178
178
  .agentchat-empty-title { margin: 0; font-size: 1.05em; color: var(--fg-2, var(--fg)); }
179
179
  .agentchat-empty-sub { margin: 0; font-size: var(--fs-sm); }
180
- .agentchat-empty-suggestions {
180
+ .agentchat-empty-suggestions, .chat-empty-suggestions {
181
181
  display: flex;
182
182
  flex-wrap: wrap;
183
183
  gap: .5em;
184
184
  justify-content: center;
185
185
  margin-top: .5em;
186
186
  }
187
- .agentchat-empty-suggestion {
187
+ .agentchat-empty-suggestion, .chat-empty-suggestion {
188
188
  cursor: pointer;
189
189
  font: inherit;
190
190
  font-size: var(--fs-tiny);
@@ -194,8 +194,8 @@
194
194
  background: color-mix(in srgb, var(--fg) 5%, transparent);
195
195
  color: var(--fg-2, var(--fg));
196
196
  }
197
- .agentchat-empty-suggestion:hover { background: color-mix(in srgb, var(--accent, var(--fg)) 12%, transparent); }
198
- .agentchat-empty-suggestion:focus-visible { outline: 2px solid var(--accent, var(--fg)); outline-offset: 2px; }
197
+ .agentchat-empty-suggestion:hover, .chat-empty-suggestion:hover { background: color-mix(in srgb, var(--accent, var(--fg)) 12%, transparent); }
198
+ .agentchat-empty-suggestion:focus-visible, .chat-empty-suggestion:focus-visible { outline: 2px solid var(--accent, var(--fg)); outline-offset: 2px; }
199
199
 
200
200
  /* Guided install path in the empty state: copy line + monospaced command rows
201
201
  (each with its own copy button) + a recheck button. No animation. */
@@ -297,8 +297,8 @@
297
297
  }
298
298
  .status-dot-disc.status-dot-live { background: var(--accent); animation: status-disc-pulse 1.8s ease-in-out infinite; }
299
299
  .status-dot-disc.status-dot-error { background: var(--flame); }
300
- .status-dot-disc.status-dot-connecting { background: var(--amber, #d9a93a); }
301
- .status-dot-disc.status-dot-stale { background: var(--amber, #d9a93a); }
300
+ .status-dot-disc.status-dot-connecting { background: var(--amber); }
301
+ .status-dot-disc.status-dot-stale { background: var(--amber); }
302
302
  @keyframes status-disc-pulse {
303
303
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 55%, transparent); }
304
304
  50% { box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 0%, transparent); }
@@ -360,7 +360,7 @@
360
360
  /* Rail tones MUST match .row.rail-* in app-shell.css so the same semantic state
361
361
  reads as one colour across the conversation list and content rows. */
362
362
  .ds-session-row.rail-green::before { background: var(--accent); }
363
- .ds-session-row.rail-purple::before { background: var(--purple-2, #7F18A4); }
363
+ .ds-session-row.rail-purple::before { background: var(--purple-2); }
364
364
  .ds-session-row.rail-flame::before { background: var(--flame); }
365
365
  .ds-session-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
366
366
  .ds-session-title { font-size: var(--fs-sm); color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -462,11 +462,16 @@ button.chat-composer-context { cursor: pointer; }
462
462
  button.chat-composer-context:hover { color: var(--fg-2); }
463
463
  button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
464
464
 
465
+ /* Composer send/cancel button row: a non-wrapping cluster pinned to the
466
+ bottom-right of the flex-end composer (was unstyled, so the send button
467
+ could wrap below the textarea instead of anchoring like claude.ai/code). */
468
+ .chat-composer-toolbar { display: flex; align-items: center; gap: var(--space-1); flex: 0 0 auto; margin-left: auto; align-self: flex-end; }
469
+
465
470
  /* --- B2: follow-up chips below the last settled assistant turn. --- */
466
471
  .agentchat-followups { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2) var(--space-3); }
467
472
 
468
473
  /* --- C1: stale/idle dashboard status (static, NOT pulsing). --- */
469
- .ds-dash-status.is-stale { color: var(--amber, #d9a93a); }
474
+ .ds-dash-status.is-stale { color: var(--amber); }
470
475
  .ds-dash-status.is-running { color: var(--accent); }
471
476
 
472
477
  /* --- C2: dashboard sort/filter toolbar + stream-state line. --- */
@@ -484,7 +489,7 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
484
489
  }
485
490
  .ds-dash-stream { font-size: var(--fs-tiny); color: var(--fg-3); }
486
491
  .ds-dash-stream.is-lost { color: var(--flame); }
487
- .ds-dash-stream.is-connecting { color: var(--amber, #d9a93a); }
492
+ .ds-dash-stream.is-connecting { color: var(--amber); }
488
493
  .ds-dash-header .spread { flex: 1; }
489
494
  .ds-dash-errors-toggle {
490
495
  padding: 4px 10px; min-height: 32px; border: var(--bw-hair) solid var(--bg-3);
@@ -510,7 +515,7 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
510
515
  /* Stale/idle card: a positive amber inset bar (mirrors is-active) so a stuck
511
516
  agent is flagged in a dense grid, not merely faded near-invisibly. The word
512
517
  'idle' co-carries state, so this stays colour-blind safe. */
513
- .ds-dash-card.is-stale { box-shadow: inset 2px 0 0 var(--amber, #d9a93a); }
518
+ .ds-dash-card.is-stale { box-shadow: inset 2px 0 0 var(--amber); }
514
519
 
515
520
  /* --- H3: dashboard live disc pulses; stale/error do not (handled by H1). --- */
516
521
 
@@ -667,7 +672,7 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
667
672
  }
668
673
 
669
674
  /* Stopping state: in-flight cancel reads distinctly from running/error. */
670
- .ds-dash-status.is-stopping { color: var(--amber, #d9a93a); }
675
+ .ds-dash-status.is-stopping { color: var(--amber); }
671
676
 
672
677
  /* External (observed, not owned) session card: no stop control exists. */
673
678
  .ds-dash-external {
@@ -699,8 +704,10 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
699
704
  .chat-msg-flat.you .chat-role { color: var(--accent); }
700
705
  .chat-msg-flat .chat-bubble { background: none; border: none; border-radius: 0; padding: 0; max-width: 100%; box-shadow: none; transform: none; }
701
706
  .chat-msg-flat.you .chat-bubble { background: none; color: inherit; }
702
- .chat-msg-flat:hover { background: color-mix(in oklab, var(--fg) 3%, transparent); }
703
- .chat-msg-flat.you:hover { background: color-mix(in oklab, var(--fg) 2%, transparent); }
707
+ /* Hover tint exceeds each role's REST tint so the row gives feedback (and the
708
+ ladder stays monotonic): assistant 5% > its 3% rest; user 4% > transparent. */
709
+ .chat-msg-flat.them:hover { background: color-mix(in oklab, var(--fg) 5%, transparent); }
710
+ .chat-msg-flat.you:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); }
704
711
  .chat-msg-flat:hover .chat-bubble { transform: none; box-shadow: none; background: none; }
705
712
  .chat-msg-flat .chat-avatar { display: none; }
706
713
 
@@ -734,6 +741,9 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
734
741
  }
735
742
  .chat-msg .chat-tool.tool-running .chat-tool-status { color: var(--accent); background: color-mix(in oklab, var(--accent) 12%, transparent); }
736
743
  .chat-msg .chat-tool.tool-error .chat-tool-status { color: var(--flame); background: color-mix(in oklab, var(--flame) 12%, transparent); }
744
+ /* Completed tool: a positive (success) tone so done reads distinctly from the
745
+ neutral pill and from the accent-toned running pill (--success = green-2). */
746
+ .chat-msg .chat-tool.tool-done .chat-tool-status { color: var(--success); background: color-mix(in oklab, var(--success) 12%, transparent); }
737
747
  .chat-tool-body { border-top: var(--bw-hair) solid var(--rule); padding: var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
738
748
  .chat-tool-section { display: flex; flex-direction: column; gap: var(--space-1); }
739
749
  .chat-tool-section-label { font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: var(--tr-caps); color: var(--fg-3); }
@@ -768,6 +778,10 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
768
778
  }
769
779
  @keyframes ds-arm-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--warn) 55%, transparent); } 100% { box-shadow: 0 0 0 6px color-mix(in oklab, var(--warn) 0%, transparent); } }
770
780
  .ds-dash-card.is-new { box-shadow: inset 2px 0 0 var(--accent), 0 0 0 1px color-mix(in oklab, var(--accent) 40%, transparent); }
781
+ /* Error card carries the strongest left-bar tone (flame > stale amber > active
782
+ accent), placed last so its inset bar wins source order over is-active/is-stale.
783
+ The full-perimeter border-color (line ~396) stays for extra severity emphasis. */
784
+ .ds-dash-card.is-error { box-shadow: inset 2px 0 0 var(--flame); }
771
785
  @media (prefers-reduced-motion: no-preference) {
772
786
  .ds-dash-card.is-new { animation: ds-card-in var(--dur-slow) var(--ease); }
773
787
  }
@@ -779,7 +793,7 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
779
793
  .ds-dash-breakdown { display: flex; align-items: center; gap: var(--space-1); font-size: var(--fs-sm); color: var(--fg-2); }
780
794
  .ds-dash-breakdown .seg.is-running { color: var(--green); font-weight: 600; }
781
795
  .ds-dash-breakdown .seg.is-error { color: var(--flame); font-weight: 600; }
782
- .ds-dash-breakdown .seg.is-idle { color: var(--amber, #d9a93a); }
796
+ .ds-dash-breakdown .seg.is-idle { color: var(--amber); }
783
797
  .ds-dash-stream-disc { display: inline-flex; align-items: center; gap: var(--space-1); }
784
798
  .ds-dash-selectall { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--fs-tiny); color: var(--fg-2); cursor: pointer; background: none; border: none; padding: var(--space-1); }
785
799
  .ds-dash-selectall:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
@@ -800,7 +814,7 @@ button.chat-composer-context:focus-visible { outline: 2px solid var(--accent); o
800
814
  .ds-preview-code code { color: var(--fg); }
801
815
  .ds-preview-code .token.comment, .ds-preview-code .token.prolog, .ds-preview-code .token.doctype, .ds-preview-code .token.cdata { color: var(--fg-3); }
802
816
  .ds-preview-code .token.punctuation { color: var(--fg-2); }
803
- .ds-preview-code .token.property, .ds-preview-code .token.tag, .ds-preview-code .token.boolean, .ds-preview-code .token.number, .ds-preview-code .token.constant, .ds-preview-code .token.symbol { color: var(--purple-2, #7F18A4); }
817
+ .ds-preview-code .token.property, .ds-preview-code .token.tag, .ds-preview-code .token.boolean, .ds-preview-code .token.number, .ds-preview-code .token.constant, .ds-preview-code .token.symbol { color: var(--purple-2); }
804
818
  .ds-preview-code .token.selector, .ds-preview-code .token.attr-name, .ds-preview-code .token.string, .ds-preview-code .token.char, .ds-preview-code .token.builtin { color: var(--code-string, var(--green)); }
805
819
  .ds-preview-code .token.atrule, .ds-preview-code .token.attr-value, .ds-preview-code .token.keyword { color: var(--code-keyword, var(--sky)); }
806
820
  .ds-preview-code .token.function, .ds-preview-code .token.class-name { color: var(--code-fn, var(--flame)); }
@@ -197,22 +197,31 @@
197
197
  --size-sm: 32px;
198
198
  --size-base: 42px;
199
199
  --size-lg: 56px;
200
+
201
+ /* Unified focus-ring tokens (single source for the design system). Outset
202
+ rings (the default) tokenize colour+width+offset; bordered text fields use
203
+ the inset variant. Deliberate negative offsets on edge-flush/clipping
204
+ containers stay literal. */
205
+ --focus-color: var(--accent);
206
+ --focus-w: 2px;
207
+ --focus-offset: 2px;
208
+ --focus-ring-inset: inset 0 0 0 var(--focus-w) var(--focus-color);
200
209
  }
201
210
 
202
211
  /* ============================================================
203
212
  Focus-visible styles for keyboard navigation
204
213
  ============================================================ */
205
214
  :focus-visible {
206
- outline: 2px solid var(--accent);
207
- outline-offset: 2px;
215
+ outline: var(--focus-w) solid var(--focus-color);
216
+ outline-offset: var(--focus-offset);
208
217
  }
209
218
 
210
219
  /* Button variants with focus-visible */
211
220
  .btn:focus-visible,
212
221
  .btn-primary:focus-visible,
213
222
  .btn-ghost:focus-visible {
214
- outline: 2px solid var(--accent);
215
- outline-offset: 2px;
223
+ outline: var(--focus-w) solid var(--focus-color);
224
+ outline-offset: var(--focus-offset);
216
225
  }
217
226
 
218
227
  /* Link focus-visible */
@@ -260,6 +269,10 @@ select:focus-visible {
260
269
  --danger: oklch(0.68 0.19 25);
261
270
  --flame: #FF5A1F;
262
271
  --amber: #D9A93A;
272
+ /* warn/sky dark-tuned pairs (mirror flame/amber): the :root paper values
273
+ (#E0241A / #3A6EFF) are too dark on ink; these clear AA 4.5:1 on --ink. */
274
+ --warn: #FF5A52;
275
+ --sky: #6E9BFF;
263
276
  --code-string: var(--green-2);
264
277
  --code-keyword: var(--sky);
265
278
  --code-fn: var(--flame);
@@ -293,6 +306,8 @@ select:focus-visible {
293
306
  --accent-bright: var(--green-2);
294
307
  --flame: #FF5A1F;
295
308
  --amber: #D9A93A;
309
+ --warn: #FF5A52;
310
+ --sky: #6E9BFF;
296
311
  --code-string: var(--green-2);
297
312
  --code-keyword: var(--sky);
298
313
  --code-fn: var(--flame);