agentgui 1.0.1021 → 1.0.1023

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.
Files changed (59) hide show
  1. package/.gm/disciplines/agentgui/memories/.flat-export-done +0 -0
  2. package/.gm/memories/.flat-export-done +1 -1
  3. package/.gm/memories/mem-0131ff4869d86085-370.md +10 -0
  4. package/.gm/memories/mem-08a4a9e050a4deff-3048.md +8 -0
  5. package/.gm/memories/mem-09597ee0df9c9224-965.md +8 -0
  6. package/.gm/memories/mem-0993d156f571b619-1059.md +8 -0
  7. package/.gm/memories/mem-0d1408fa048b9923-1159.md +8 -0
  8. package/.gm/memories/mem-1781870426883-0-2340.md +8 -0
  9. package/.gm/memories/mem-1781943679146-0-1577.md +8 -0
  10. package/.gm/memories/mem-1781943722930-1-2318.md +8 -0
  11. package/.gm/memories/mem-1781943733304-2-2135.md +8 -0
  12. package/.gm/memories/mem-1781946701659-3-1665.md +8 -0
  13. package/.gm/memories/mem-1781952323283-0-2146.md +8 -0
  14. package/.gm/memories/mem-1781961165110-1-2041.md +8 -0
  15. package/.gm/memories/mem-1781966495635-2-1606.md +8 -0
  16. package/.gm/memories/mem-39a7cc2f887a90b1-1079.md +8 -0
  17. package/.gm/memories/mem-4bafafa47a0e4b6c-3237.md +8 -0
  18. package/.gm/memories/mem-4c06c45b4d31bc60-1202.md +8 -0
  19. package/.gm/memories/mem-4ecd3b713e384170-122.md +10 -0
  20. package/.gm/memories/mem-51d8992a3c6f6c9c-1073.md +8 -0
  21. package/.gm/memories/mem-539eee7e8c6c10ee-2557.md +8 -0
  22. package/.gm/memories/mem-6224f8d185797f2b-1047.md +8 -0
  23. package/.gm/memories/mem-66b0947b946f3437-1155.md +8 -0
  24. package/.gm/memories/mem-6bdf783a1f6be7c2-1062.md +8 -0
  25. package/.gm/memories/mem-70d96acb736af2d7-685.md +8 -0
  26. package/.gm/memories/mem-7535f34f430fc196-1340.md +8 -0
  27. package/.gm/memories/mem-861a588d2773681a-1311.md +8 -0
  28. package/.gm/memories/mem-9329105b05b9c0f6-324.md +10 -0
  29. package/.gm/memories/mem-94f30cec3c283f97-782.md +10 -0
  30. package/.gm/memories/mem-956d4813319f65a3-1710.md +8 -0
  31. package/.gm/memories/mem-a52933cd6495e6f5-2624.md +8 -0
  32. package/.gm/memories/mem-a95b1d49d71133ce-1007.md +8 -0
  33. package/.gm/memories/mem-aaeae38d8eb01809-1076.md +8 -0
  34. package/.gm/memories/mem-b06b8c85b81663e6-1250.md +8 -0
  35. package/.gm/memories/mem-bdf466854032cac9-1509.md +8 -0
  36. package/.gm/memories/mem-cda639547932c796-713.md +8 -0
  37. package/.gm/memories/mem-cf8472c84d9e04c4-1883.md +8 -0
  38. package/.gm/memories/mem-d060480435f92eec-1146.md +8 -0
  39. package/.gm/memories/mem-d347c921b79e6d44-1099.md +8 -0
  40. package/.gm/memories/mem-d3c8ea6c861bfbb8-1457.md +8 -0
  41. package/.gm/memories/mem-d5e928c552cd87f9-214.md +10 -0
  42. package/.gm/memories/mem-d63bc3b8a0269844-406.md +10 -0
  43. package/.gm/memories/mem-da1c91acf63d81d3-863.md +8 -0
  44. package/.gm/memories/mem-dceeae20bc56d407-711.md +8 -0
  45. package/.gm/memories/mem-df74674eec7745ac-178.md +10 -0
  46. package/.gm/memories/mem-e1d5431ae2542872-961.md +8 -0
  47. package/.gm/memories/mem-ebbe6c0694c526f0-1392.md +8 -0
  48. package/.gm/memories/mem-ebf85becc23410b0-1633.md +8 -0
  49. package/.gm/memories/mem-ee8858162518f144-1252.md +8 -0
  50. package/.gm/memories/mem-f3f317c083d979ee-1210.md +8 -0
  51. package/.gm/memories/mem-f786bc1626d92845-204.md +10 -0
  52. package/.gm/memories/mem-ff8669e527e5c427-2788.md +8 -0
  53. package/.gm/prd.yml +96 -0
  54. package/AGENTS.md +4 -0
  55. package/package.json +1 -1
  56. package/site/app/index.html +4 -0
  57. package/site/app/js/app.js +56 -28
  58. package/site/app/vendor/anentrypoint-design/247420.css +1286 -213
  59. package/site/app/vendor/anentrypoint-design/247420.js +32 -33
@@ -7,19 +7,9 @@
7
7
  Source-of-truth tokens. Component sheet lives in app-shell.css.
8
8
  ============================================================ */
9
9
 
10
- @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400;1,700&display=swap');
11
-
12
- /* Metric-matched fallback for the display face. While Space Grotesk loads,
13
- text falls back to Arial with size-adjust tuned to its cap-height so the
14
- oversized hero does not reflow on swap. Referenced first in --ff-display via
15
- the 'Space Grotesk' family; this only kicks in for the fallback glyphs. */
16
- @font-face {
17
- font-family: 'Space Grotesk Fallback';
18
- src: local('Arial');
19
- size-adjust: 96%;
20
- ascent-override: 95%;
21
- descent-override: 24%;
22
- }
10
+ /* System-font stack only — no web-font @import/@font-face. Every --ff-*
11
+ token below is the same fallback chain that used to sit after the custom
12
+ family names; removing the custom names just exposes it directly. */
23
13
 
24
14
  .ds-247420 {
25
15
  /* Tree view indentation tokens */
@@ -131,14 +121,11 @@
131
121
  --panel-accent-2: var(--accent-bright, var(--accent));
132
122
  --panel-shadow: 0 1px 0 color-mix(in oklab, var(--fg) 6%, transparent), 0 4px 14px color-mix(in oklab, var(--fg) 8%, transparent);
133
123
 
134
- /* Type — Space Grotesk carries display/headings (editorial grotesk with real
135
- character), Inter carries body and UI, JetBrains carries code. The narrow
136
- alias tracks the display face. size-adjust on the fallback keeps the
137
- oversized hero from shifting while Space Grotesk loads. */
138
- --ff-display: 'Space Grotesk', 'Space Grotesk Fallback', 'Inter', system-ui, sans-serif;
139
- --ff-narrow: 'Space Grotesk', 'Space Grotesk Fallback', 'Inter', system-ui, sans-serif;
140
- --ff-body: 'Inter', system-ui, sans-serif;
141
- --ff-mono: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;
124
+ /* Type — system-font stack, no custom web fonts loaded. */
125
+ --ff-display: system-ui, sans-serif;
126
+ --ff-narrow: system-ui, sans-serif;
127
+ --ff-body: system-ui, sans-serif;
128
+ --ff-mono: ui-monospace, Menlo, Consolas, monospace;
142
129
 
143
130
  --fs-micro: 12px;
144
131
  --fs-tiny: 13px;
@@ -174,9 +161,17 @@
174
161
  --tr-tighter: -0.03em;
175
162
 
176
163
  /* Spacing (8pt) */
164
+ /* Micro rungs below --space-1 — dense editor/inspector chrome (table cell
165
+ padding, pill gaps, tight toolbar gutters) needs finer steps than the 8pt
166
+ scale offers; same reasoning as --r-hair/--r-0 sitting below --r-1. */
167
+ --space-hair: 2px;
168
+ --space-half: 3px;
177
169
  --space-0: 0;
178
170
  --space-1: 4px;
171
+ --space-1-5: 5px;
172
+ --space-1-75: 6px;
179
173
  --space-2: 8px;
174
+ --space-2-5: 10px;
180
175
  --space-3: 16px;
181
176
  --space-4: 24px;
182
177
  --space-5: 32px;
@@ -200,10 +195,14 @@
200
195
  --rule: color-mix(in oklab, currentColor 14%, transparent);
201
196
  --rule-strong: color-mix(in oklab, currentColor 28%, transparent);
202
197
 
198
+ /* Micro rungs below --r-1 — chips, badges, scrollbar thumbs, tick marks
199
+ genuinely want a tighter corner than 10px; without these two tokens the
200
+ component sheets fell back to raw px literals bypassing the scale. */
201
+ --r-hair: 2px;
202
+ --r-0: 4px;
203
203
  --r-1: 10px;
204
204
  --r-2: 14px;
205
205
  --r-3: 22px;
206
- --r-4: 32px;
207
206
  --r-pill: 999px;
208
207
 
209
208
  --dur-snap: 80ms;
@@ -233,6 +232,10 @@
233
232
  --measure: 68ch;
234
233
  --measure-wide: 940px;
235
234
  --measure-narrow: 760px;
235
+ /* Page-stage ceiling — independent of --measure-wide (which stays the
236
+ narrower editorial hero/prose measure). Fluid so ultra-wide viewports
237
+ actually gain real estate instead of flat-lining at a fixed px cap. */
238
+ --stage-wide: min(96vw, 1440px);
236
239
 
237
240
  --sidebar-width: 220px;
238
241
  --sidebar-width-collapsed: 64px;
@@ -247,8 +250,11 @@
247
250
  /* Unified focus-ring tokens (single source for the design system). Outset
248
251
  rings (the default) tokenize colour+width+offset; bordered text fields use
249
252
  the inset variant. Deliberate negative offsets on edge-flush/clipping
250
- containers stay literal. */
251
- --focus-color: var(--accent);
253
+ containers stay literal. --focus-color uses --accent-ink (the readable
254
+ text/UI-boundary tone), never bare --accent (the lime FILL token, which
255
+ measures ~1.07:1 against --paper and is nearly invisible as an outline —
256
+ see AGENTS.md token-split rule). */
257
+ --focus-color: var(--accent-ink);
252
258
  --focus-w: 2px;
253
259
  --focus-offset: 2px;
254
260
  --focus-ring-inset: inset 0 0 0 var(--focus-w) var(--focus-color);
@@ -273,7 +279,7 @@
273
279
  /* Link focus-visible */
274
280
  .ds-247420 a:focus-visible,
275
281
  .ds-247420[role="link"]:focus-visible {
276
- outline: 2px solid var(--accent);
282
+ outline: 2px solid var(--accent-ink);
277
283
  outline-offset: 2px;
278
284
  }
279
285
 
@@ -281,13 +287,13 @@
281
287
  .ds-247420 input:focus-visible,
282
288
  .ds-247420 textarea:focus-visible,
283
289
  .ds-247420 select:focus-visible {
284
- outline: 2px solid var(--accent);
290
+ outline: 2px solid var(--accent-ink);
285
291
  outline-offset: 2px;
286
292
  }
287
293
 
288
294
  /* Interactive element focus-visible */
289
295
  .ds-247420[tabindex]:focus-visible {
290
- outline: 2px solid var(--accent);
296
+ outline: 2px solid var(--accent-ink);
291
297
  outline-offset: 2px;
292
298
  }
293
299
 
@@ -500,7 +506,7 @@
500
506
  /* app-shell.css */
501
507
  /* ============================================================
502
508
  247420 design system — component sheet
503
- "Acid Editorial": Space Grotesk display + Inter body + JetBrains code.
509
+ "Acid Editorial": system-font display + body + mono, no custom web fonts.
504
510
  Confident hierarchy, asymmetric grid tension, print texture over glow,
505
511
  one electric lead accent. Indicator rails over hairlines.
506
512
  ============================================================ */
@@ -530,7 +536,7 @@
530
536
  }
531
537
  .ds-247420 .skip-link:focus {
532
538
  top: 10px;
533
- outline: 2px solid var(--accent);
539
+ outline: 2px solid var(--accent-ink);
534
540
  outline-offset: 2px;
535
541
  }
536
542
  .ds-247420 body {
@@ -747,7 +753,7 @@
747
753
  }
748
754
  .ds-247420 .app-topbar nav a:hover { background: var(--bg-2); color: var(--fg); }
749
755
  .ds-247420 .app-topbar nav a:focus-visible {
750
- outline: 2px solid var(--accent);
756
+ outline: 2px solid var(--accent-ink);
751
757
  outline-offset: 2px;
752
758
  }
753
759
  /* Active tab reads as a subtle tinted pill with an accent underline rather than
@@ -783,7 +789,7 @@
783
789
  width: 100%;
784
790
  }
785
791
  .ds-247420 .app-search:focus-within {
786
- outline: 2px solid var(--accent);
792
+ outline: 2px solid var(--accent-ink);
787
793
  outline-offset: 2px;
788
794
  }
789
795
 
@@ -825,7 +831,7 @@
825
831
  }
826
832
  .ds-247420 .app-side a:hover { background: var(--bg-2); color: var(--fg); }
827
833
  .ds-247420 .app-side a:focus-visible {
828
- outline: 2px solid var(--accent);
834
+ outline: 2px solid var(--accent-ink);
829
835
  outline-offset: 2px;
830
836
  }
831
837
  .ds-247420 .app-side a.active {
@@ -871,17 +877,31 @@
871
877
  .ds-247420 .app-main > .chat,
872
878
  .ds-247420 .app-main > .chat-area,
873
879
  .ds-247420 .app-main > .ds-file-stage,
880
+ .ds-247420 .app-main > .ds-files-stack,
874
881
  .ds-247420 .app-main > .grow { flex: 1 1 auto; min-height: 0; }
875
882
  .ds-247420 .app-main.narrow { max-width: var(--measure-narrow); margin: 0 auto; }
876
883
 
877
884
  @media (min-width: 1400px) {
878
- .ds-247420 .app { max-width: 1400px; margin-left: auto; margin-right: auto; }
885
+ /* Fluid ceiling, not a hard stop: scales from 1400px up to 1920px across the
886
+ 1400-2200px viewport band (matches .ws-shell's 1920px ultrawide cap below)
887
+ instead of freezing at 1400px and leaving >1000px dead margin on a 2560px+
888
+ display. Row/prose measure caps (--measure-wide etc.) still own line-length
889
+ readability, so widening the shell itself does not create unreadable rows. */
890
+ .ds-247420 .app { max-width: clamp(1400px, 92vw, 1920px); margin-left: auto; margin-right: auto; }
879
891
  .ds-247420 .app-main .chat,
880
892
  .ds-247420 .app-main > .chat-area,
881
893
  .ds-247420 .app-main > .main-content { max-width: none; margin: 0; width: 100%; }
882
894
  /* Status bar inherits the .app max-width cap above and stretches edge-to-edge
883
895
  within it; no separate width constraint (which previously narrowed it). */
884
896
  .ds-247420 .app-status { width: 100%; }
897
+ /* Cap row text measure inside the wide capped main (ultrawide readability). */
898
+ .ds-247420 .row .title, .ds-247420 .row .sub { max-width: var(--measure-wide); }
899
+ }
900
+ /* Beyond 1920px the shell itself stops growing (matches .ws-shell's own cap) —
901
+ extra space becomes page margin rather than stretching sidebar/content grid
902
+ tracks to distances a pointer/eye shouldn't have to travel. */
903
+ @media (min-width: 2200px) {
904
+ .ds-247420 .app { max-width: 1920px; }
885
905
  }
886
906
 
887
907
  .ds-247420 .app-status {
@@ -934,7 +954,7 @@
934
954
  .ds-247420 .btn-ghost:hover { background: var(--fg); color: var(--bg); }
935
955
  .ds-247420 .btn:active, .ds-247420 .btn-primary:active, .ds-247420 .btn-ghost:active { transform: translateY(2px); }
936
956
  .ds-247420 .btn:focus-visible, .ds-247420 .btn-primary:focus-visible, .ds-247420 .btn-ghost:focus-visible {
937
- outline: 2px solid var(--accent);
957
+ outline: 2px solid var(--accent-ink);
938
958
  outline-offset: 2px;
939
959
  }
940
960
 
@@ -961,7 +981,7 @@
961
981
  .ds-247420 .ds-icon-btn-danger { background: var(--warn); color: var(--on-color); }
962
982
  .ds-247420 .ds-icon-btn-danger:hover { filter: brightness(1.1); }
963
983
  .ds-247420 .ds-icon-btn:active { transform: translateY(1px); }
964
- .ds-247420 .ds-icon-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
984
+ .ds-247420 .ds-icon-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
965
985
  .ds-247420 .ds-icon-btn:disabled, .ds-247420 .ds-icon-btn.is-disabled {
966
986
  opacity: 0.5; cursor: not-allowed; pointer-events: none;
967
987
  }
@@ -973,7 +993,7 @@
973
993
  display: inline-flex; align-items: center; justify-content: center;
974
994
  min-width: 18px; height: 18px; padding: 0 6px;
975
995
  font-size: var(--fs-micro); font-weight: 600; line-height: 1;
976
- border-radius: 999px;
996
+ border-radius: var(--r-pill);
977
997
  background: var(--bg-3); color: var(--fg-2);
978
998
  }
979
999
  .ds-247420 .ds-badge.tone-green { background: var(--green-tint); color: var(--green-deep); }
@@ -986,6 +1006,9 @@
986
1006
  .ds-247420 .ds-badge.tone-error { background: var(--flame); color: var(--on-color); }
987
1007
  .ds-247420 .ds-badge.tone-success { background: var(--green-tint); color: var(--green-deep); }
988
1008
  .ds-247420 .ds-badge.tone-neutral { background: var(--bg-3); color: var(--fg-2); }
1009
+ .ds-247420 .ds-badge.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
1010
+ .ds-247420 .ds-badge.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
1011
+ .ds-247420 .ds-badge.tone-yellow { background: var(--sun); color: var(--ink); }
989
1012
 
990
1013
  .ds-247420 .chip {
991
1014
  display: inline-flex; align-items: center; gap: 6px;
@@ -1009,6 +1032,22 @@
1009
1032
  .ds-247420 .chip.tone-ok { background: var(--green-tint); color: var(--green-deep); }
1010
1033
  .ds-247420 .chip.tone-miss { background: var(--flame); color: var(--on-color); }
1011
1034
  .ds-247420 .chip.tone-neutral { background: var(--bg-3); color: var(--fg-2); }
1035
+ .ds-247420 .chip.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
1036
+ .ds-247420 .chip.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
1037
+ .ds-247420 .chip.tone-yellow { background: var(--sun); color: var(--ink); }
1038
+
1039
+ /* ds-pill — plain neutral chip, distinct from the toned .ds-badge/.chip family
1040
+ (gmsniff's .pill: a bare rounded label with no semantic tone). */
1041
+ .ds-247420 .ds-pill {
1042
+ display: inline-block;
1043
+ padding: 1px 7px;
1044
+ border-radius: var(--r-pill);
1045
+ font-size: var(--fs-micro);
1046
+ background: var(--bg-3); color: var(--fg-2);
1047
+ margin: 1px;
1048
+ }
1049
+ .ds-247420 .ds-pill.tone-accent { background: var(--accent-tint); color: var(--accent-ink); }
1050
+ .ds-247420 .ds-pill.tone-muted { background: transparent; color: var(--fg-3); box-shadow: inset 0 0 0 1px var(--rule); }
1012
1051
 
1013
1052
  .ds-247420 .glyph {
1014
1053
  display: inline-flex; align-items: center; justify-content: center;
@@ -1047,7 +1086,7 @@
1047
1086
  rows sit on ONE left axis (the old 24/32 padding was authored for the
1048
1087
  pre-padding .panel-wide era and indented the label 16px past its content). */
1049
1088
  padding: var(--space-2) var(--space-3);
1050
- font-size: var(--fs-xs); font-weight: 600;
1089
+ font-size: var(--fs-tiny); font-weight: 600;
1051
1090
  color: var(--fg-3);
1052
1091
  letter-spacing: var(--tr-caps); text-transform: uppercase;
1053
1092
  }
@@ -1175,7 +1214,6 @@
1175
1214
  .ds-247420 .ds-hero-head { grid-area: title; display: grid; gap: var(--space-3); }
1176
1215
  .ds-247420 .ds-hero-body { grid-area: body; }
1177
1216
  .ds-247420 .ds-hero-actions { grid-area: actions; }
1178
- .ds-247420 .ds-hero-badge { grid-area: actions; }
1179
1217
  .ds-247420 .ds-hero-title {
1180
1218
  font-family: var(--ff-display); font-weight: 700;
1181
1219
  font-size: clamp(40px, 9cqi, 116px);
@@ -1190,7 +1228,10 @@
1190
1228
  /* The lead phrase in the title — printed in the electric lead, not glowing. */
1191
1229
  .ds-247420 .ds-hero-accent { color: var(--accent-ink); font-weight: 700; }
1192
1230
  .ds-247420 .ds-hero-actions { display: flex; gap: var(--space-2, 10px); flex-wrap: wrap; align-self: end; }
1193
- @media (max-width: 900px) {
1231
+ /* Container-queried (the whole shell is; a 500px pane on a wide viewport
1232
+ would keep the two-column grid under a width @media). Left-aligned stack —
1233
+ no centering — preserving the asymmetric intent. */
1234
+ @container (max-width: 900px) {
1194
1235
  .ds-247420 .ds-hero {
1195
1236
  grid-template-columns: minmax(0, 1fr);
1196
1237
  grid-template-areas: 'title' 'body' 'actions';
@@ -1261,13 +1302,21 @@
1261
1302
  }
1262
1303
  .ds-247420 .ds-marquee-item { display: inline-flex; align-items: center; gap: var(--space-5); }
1263
1304
  .ds-247420 .ds-marquee-sep { color: var(--accent-ink); }
1264
- .ds-247420 .ds-marquee:hover .ds-marquee-track { animation-play-state: paused; }
1305
+ .ds-247420 .ds-marquee:hover .ds-marquee-track,
1306
+ .ds-247420 .ds-marquee:focus-within .ds-marquee-track,
1307
+ .ds-247420 .ds-marquee:active .ds-marquee-track { animation-play-state: paused; }
1265
1308
  @keyframes ds-marquee-run {
1266
1309
  from { transform: translateX(0); }
1267
1310
  to { transform: translateX(-50%); }
1268
1311
  }
1312
+ /* Touch has no hover-pause; slow the ticker so it burns less attention. */
1313
+ @media (hover: none), (pointer: coarse) {
1314
+ .ds-247420 .ds-marquee-track { animation-duration: 40s; }
1315
+ }
1269
1316
  @media (prefers-reduced-motion: reduce) {
1270
- .ds-247420 .ds-marquee-track { animation: none; }
1317
+ /* Static: wrap to a readable strip instead of a frozen half-offscreen run. */
1318
+ .ds-247420 .ds-marquee-track { animation: none; flex-wrap: wrap; white-space: normal; }
1319
+ .ds-247420 .ds-marquee-run-b { display: none; }
1271
1320
  }
1272
1321
 
1273
1322
  /* ============================================================
@@ -1275,6 +1324,7 @@
1275
1324
  ============================================================ */
1276
1325
  .ds-247420 .cli {
1277
1326
  display: flex; align-items: center; gap: 14px;
1327
+ overflow-x: auto;
1278
1328
  padding: 20px 24px;
1279
1329
  background: var(--ink); color: var(--paper);
1280
1330
  border-radius: var(--r-3);
@@ -1290,22 +1340,23 @@
1290
1340
  }
1291
1341
  .ds-247420 .cli .copy:hover { background: var(--fg-3); }
1292
1342
 
1293
- /* Multi-line CLI block: when .cli holds .cli-line / .cli-cmt children
1294
- (quickstart scripts, multi-command snippets) it stacks as a column
1295
- instead of the single-line install row. */
1296
- .ds-247420 .cli:has(.cli-line),
1297
- .ds-247420 .cli:has(.cli-cmt) {
1343
+ /* Multi-line CLI block: when .cli holds .ds-cli-row / .ds-cli-comment children
1344
+ (quickstart scripts, multi-command snippets see CliBlock in
1345
+ src/components/content.js) it stacks as a column instead of the
1346
+ single-line install row. */
1347
+ .ds-247420 .cli:has(.ds-cli-row),
1348
+ .ds-247420 .cli:has(.ds-cli-comment) {
1298
1349
  flex-direction: column; align-items: stretch; gap: 0;
1299
1350
  font-size: var(--fs-sm); line-height: 1.6;
1300
1351
  }
1301
- .ds-247420 .cli-line {
1352
+ .ds-247420 .ds-cli-row {
1302
1353
  display: flex; gap: 10px;
1303
1354
  font-family: var(--ff-mono); font-size: 13px; line-height: 1.6;
1304
1355
  padding: 3px 0;
1305
1356
  }
1306
- .ds-247420 .cli-line .prompt { color: var(--green-2); flex: 0 0 auto; user-select: none; }
1307
- .ds-247420 .cli-line .cmd { flex: 1 1 auto; white-space: pre-wrap; word-break: break-word; color: var(--paper); }
1308
- .ds-247420 .cli-cmt {
1357
+ .ds-247420 .ds-cli-row .prompt { color: var(--green-2); flex: 0 0 auto; user-select: none; }
1358
+ .ds-247420 .ds-cli-row .cmd { flex: 1 1 auto; white-space: pre-wrap; word-break: break-word; color: var(--paper); }
1359
+ .ds-247420 .ds-cli-comment {
1309
1360
  color: var(--fg-3);
1310
1361
  font-family: var(--ff-mono); font-size: var(--fs-tiny); line-height: 1.6;
1311
1362
  padding: 3px 0; white-space: pre-wrap; word-break: break-word;
@@ -1328,6 +1379,15 @@
1328
1379
  }
1329
1380
  .ds-247420 table.kv td:last-child {
1330
1381
  font-weight: 600;
1382
+ overflow-wrap: anywhere; min-width: 0;
1383
+ }
1384
+ /* Tiny screens: stack the key over the value instead of squeezing a 14ch
1385
+ label column beside long unbroken values (URLs, hashes). */
1386
+ @media (max-width: 400px) {
1387
+ .ds-247420 table.kv td { display: block; width: auto; padding: 4px 0; }
1388
+ .ds-247420 table.kv td:first-child { padding-top: 8px; }
1389
+ .ds-247420 table.kv tr + tr td { border-top: 0; }
1390
+ .ds-247420 table.kv tr + tr td:first-child { border-top: 1px solid var(--rule); }
1331
1391
  }
1332
1392
 
1333
1393
  /* ============================================================
@@ -1341,7 +1401,7 @@
1341
1401
  .ds-247420 table th {
1342
1402
  text-align: left;
1343
1403
  padding: 12px 16px;
1344
- font-size: var(--fs-xs); font-weight: 600;
1404
+ font-size: var(--fs-tiny); font-weight: 600;
1345
1405
  color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-caps);
1346
1406
  background: var(--bg-2);
1347
1407
  }
@@ -1349,7 +1409,7 @@
1349
1409
  .ds-247420 table tr.clickable { cursor: pointer; }
1350
1410
  .ds-247420 table tr.clickable:hover td { background: var(--bg-2); }
1351
1411
  .ds-247420 table tr.clickable:focus-visible {
1352
- outline: 2px solid var(--accent);
1412
+ outline: 2px solid var(--accent-ink);
1353
1413
  outline-offset: -2px;
1354
1414
  }
1355
1415
  .ds-247420 table tr.clickable:focus-visible td { background: var(--bg-2); }
@@ -1418,6 +1478,41 @@
1418
1478
  font-weight: 600; margin-top: 8px;
1419
1479
  letter-spacing: var(--tr-caps); text-transform: uppercase;
1420
1480
  }
1481
+ .ds-247420 .kpi-foot {
1482
+ display: flex; align-items: center; justify-content: space-between;
1483
+ margin-top: var(--space-2);
1484
+ }
1485
+ .ds-247420 .kpi-delta {
1486
+ display: inline-flex; align-items: center; gap: var(--space-hair);
1487
+ font-size: var(--fs-xs); font-weight: 600;
1488
+ }
1489
+ .ds-247420 .kpi-delta-up { color: var(--success); }
1490
+ .ds-247420 .kpi-delta-down { color: var(--danger); }
1491
+ .ds-247420 .ds-sparkline path { stroke: currentColor; }
1492
+ .ds-247420 .ds-sparkline-up { color: var(--success); }
1493
+ .ds-247420 .ds-sparkline-down { color: var(--danger); }
1494
+
1495
+ /* ============================================================
1496
+ BarChart
1497
+ ============================================================ */
1498
+ .ds-247420 .ds-barchart { display: flex; flex-direction: column; gap: var(--space-2); }
1499
+ .ds-247420 .ds-barchart-row {
1500
+ display: grid; grid-template-columns: minmax(90px, 25%) 1fr auto;
1501
+ align-items: center; gap: var(--space-2);
1502
+ }
1503
+ .ds-247420 .ds-barchart-label { font-size: var(--fs-sm); color: var(--fg-2); }
1504
+ .ds-247420 .ds-barchart-track {
1505
+ height: var(--space-2); border-radius: var(--r-pill);
1506
+ background: var(--bg-3); overflow: hidden;
1507
+ }
1508
+ .ds-247420 .ds-barchart-fill {
1509
+ height: 100%; width: var(--bar-pct, 0%);
1510
+ background: var(--accent); border-radius: var(--r-pill);
1511
+ }
1512
+ .ds-247420 .ds-barchart-value {
1513
+ font-size: var(--fs-xs); font-weight: 600; color: var(--fg-3);
1514
+ font-variant-numeric: tabular-nums;
1515
+ }
1421
1516
 
1422
1517
  /* ============================================================
1423
1518
  Empty state
@@ -1523,6 +1618,10 @@
1523
1618
  }
1524
1619
  .ds-247420 .row .sub { grid-column: 1 / -1; order: 3; }
1525
1620
  .ds-247420 .row .title { font-size: var(--fs-sm); }
1621
+ /* Changelog carries 3 children: give date+ver line one, message wraps below
1622
+ (the generic 2-col .row override staggers it into an implicit row). */
1623
+ .ds-247420 .ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
1624
+ .ds-247420 .ds-changelog-row .title { grid-column: 1 / -1; }
1526
1625
 
1527
1626
  /* Buttons */
1528
1627
  .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
@@ -1566,7 +1665,9 @@
1566
1665
  gap: var(--space-2);
1567
1666
  }
1568
1667
  .ds-247420 .kpi-card { padding: var(--space-3); }
1569
- .ds-247420 .kpi-card .num { font-size: clamp(22px, 5vw, 32px); }
1668
+ /* Container-relative like the base rule (5vw sized against the viewport and
1669
+ jumped across the breakpoint). */
1670
+ .ds-247420 .kpi-card .num { font-size: clamp(22px, 8cqi, 32px); }
1570
1671
 
1571
1672
  /* Empty State */
1572
1673
  .ds-247420 .empty { padding: var(--space-5); font-size: var(--fs-xs); }
@@ -1600,10 +1701,11 @@
1600
1701
  @container (max-width: 760px) {
1601
1702
  .ds-247420 .app-body { grid-template-columns: 1fr !important; }
1602
1703
  .ds-247420 .app-side-shell { border-right: 0; border-bottom: 1px solid var(--rule); }
1603
- .ds-247420 .app-topbar { grid-template-columns: 1fr auto; }
1604
1704
  .ds-247420 .app-topbar nav { font-size: var(--fs-xs); gap: 14px; }
1605
1705
  .ds-247420 .row { grid-template-columns: minmax(0, 1fr) auto !important; row-gap: 4px !important; }
1606
1706
  .ds-247420 .row .sub { grid-column: 1 / -1; order: 3; }
1707
+ .ds-247420 .ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
1708
+ .ds-247420 .ds-changelog-row .title { grid-column: 1 / -1; }
1607
1709
  }
1608
1710
 
1609
1711
  /* --------------------------------------------------------------------
@@ -1618,9 +1720,8 @@
1618
1720
  min-height: 44px;
1619
1721
  }
1620
1722
 
1621
- /* Topbar Navigation */
1723
+ /* Topbar Navigation (flex container — no grid-template here) */
1622
1724
  .ds-247420 .app-topbar {
1623
- grid-template-columns: auto 1fr auto;
1624
1725
  gap: var(--space-3); padding: 12px var(--space-4);
1625
1726
  }
1626
1727
  .ds-247420 .app-topbar nav {
@@ -1699,6 +1800,8 @@
1699
1800
  gap: var(--space-2);
1700
1801
  }
1701
1802
  .ds-247420 .row .code { display: none; }
1803
+ /* Changelog's date lives in span.code — hiding it is data loss, not reflow. */
1804
+ .ds-247420 .ds-changelog-row .code { display: inline; font-size: var(--fs-micro); }
1702
1805
  .ds-247420 .row .sub { grid-column: 1 / -1; }
1703
1806
  }
1704
1807
 
@@ -1739,7 +1842,7 @@
1739
1842
  flex-direction: column;
1740
1843
  gap: 4px;
1741
1844
  }
1742
- .ds-247420 .ds-file-grid:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-2); }
1845
+ .ds-247420 .ds-file-grid:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-2); }
1743
1846
 
1744
1847
  /* Listing wrapper holds the optional filter + sort header above the grid. */
1745
1848
  .ds-247420 .ds-file-listing { display: flex; flex-direction: column; gap: var(--space-2); min-height: 0; }
@@ -1761,7 +1864,7 @@
1761
1864
  }
1762
1865
  .ds-247420 .ds-file-sort-btn:hover { color: var(--fg-2); background: var(--bg-2); }
1763
1866
  .ds-247420 .ds-file-sort-btn.active { color: var(--accent-ink); }
1764
- .ds-247420 .ds-file-sort-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
1867
+ .ds-247420 .ds-file-sort-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
1765
1868
 
1766
1869
  /* Skeleton shimmer rows shown while a directory loads. */
1767
1870
  .ds-247420 .ds-file-row-skeleton { cursor: default; pointer-events: none; }
@@ -1809,7 +1912,7 @@
1809
1912
  color: inherit; font: inherit; text-align: left; cursor: pointer;
1810
1913
  }
1811
1914
  .ds-247420 .ds-file-open[disabled] { cursor: default; }
1812
- .ds-247420 .ds-file-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-1); }
1915
+ .ds-247420 .ds-file-open:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-1); }
1813
1916
  .ds-247420 .ds-file-row:hover {
1814
1917
  background: var(--bg-2);
1815
1918
  border-color: var(--rule);
@@ -1882,7 +1985,7 @@
1882
1985
  role=checkbox/aria-checked name+state. */
1883
1986
  .ds-247420 .ds-check-box {
1884
1987
  width: 15px; height: 15px; box-sizing: border-box; flex: 0 0 auto; position: relative;
1885
- border: 1.5px solid var(--fg-3); border-radius: 4px;
1988
+ border: 1.5px solid var(--fg-3); border-radius: var(--r-0);
1886
1989
  transition: background var(--dur-snap) var(--ease), border-color var(--dur-snap) var(--ease);
1887
1990
  }
1888
1991
  .ds-247420 .is-marked > .ds-check-box,
@@ -1894,7 +1997,7 @@
1894
1997
  }
1895
1998
  .ds-247420[aria-checked="mixed"] > .ds-check-box { background: var(--accent); border-color: var(--accent); }
1896
1999
  .ds-247420[aria-checked="mixed"] > .ds-check-box::after {
1897
- content: ""; position: absolute; left: 3px; right: 3px; top: 6px; height: 2px; background: var(--bg); border-radius: 1px;
2000
+ content: ""; position: absolute; left: 3px; right: 3px; top: 6px; height: 2px; background: var(--bg); border-radius: var(--r-hair);
1898
2001
  }
1899
2002
 
1900
2003
  .ds-247420 .ds-file-check {
@@ -1907,7 +2010,7 @@
1907
2010
  }
1908
2011
  .ds-247420 .ds-file-check:hover { background: var(--bg-3); color: var(--fg); }
1909
2012
  .ds-247420 .ds-file-check.is-marked { color: var(--accent-ink); }
1910
- .ds-247420 .ds-file-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
2013
+ .ds-247420 .ds-file-check:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
1911
2014
  .ds-247420 .ds-file-check[disabled] { opacity: 0.4; cursor: default; }
1912
2015
  .ds-247420 .ds-file-row.is-marked { background: var(--accent-tint); border-color: var(--accent); }
1913
2016
  .ds-247420 .ds-file-selectall {
@@ -1917,7 +2020,7 @@
1917
2020
  padding: var(--space-1); border-radius: var(--r-1);
1918
2021
  }
1919
2022
  .ds-247420 .ds-file-selectall:hover { background: var(--bg-2); color: var(--fg); }
1920
- .ds-247420 .ds-file-selectall:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
2023
+ .ds-247420 .ds-file-selectall:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
1921
2024
  .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; }
1922
2025
  .ds-247420 .ds-file-controls .spread { flex: 1 1 auto; }
1923
2026
  .ds-247420 .ds-file-controls .ds-file-sort { padding: 0; }
@@ -1955,7 +2058,7 @@
1955
2058
  }
1956
2059
  .ds-247420 .ds-density-btn:hover { color: var(--fg); }
1957
2060
  .ds-247420 .ds-density-btn.active { background: var(--accent-tint); color: var(--fg); }
1958
- .ds-247420 .ds-density-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
2061
+ .ds-247420 .ds-density-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
1959
2062
 
1960
2063
  /* Compact density — tighter rows for long listings. */
1961
2064
  .ds-247420 .ds-file-grid[data-density="compact"] { gap: 2px; }
@@ -1981,15 +2084,19 @@
1981
2084
  .ds-247420 .ds-file-cell.is-locked { opacity: 0.6; }
1982
2085
  .ds-247420 .ds-file-row.is-locked { opacity: 0.6; }
1983
2086
  .ds-247420 .ds-file-row.is-restricted .title { color: var(--fg-2); }
2087
+ /* A fourth, deliberately bordered/mono tag variant for file-permission tags
2088
+ specifically (distinct from .ds-badge for numeric counts and .chip for
2089
+ status/label words) - is-noaccess reuses the shared --flame tone token
2090
+ so 'no access' reads the same red as chip.tone-error/miss elsewhere. */
1984
2091
  .ds-247420 .ds-file-perm-tag { font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-3); padding: 1px 6px; border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1); white-space: nowrap; }
1985
- .ds-247420 .ds-file-perm-tag.is-noaccess { color: var(--flame); border-color: color-mix(in srgb, var(--flame) 40%, transparent); }
2092
+ .ds-247420 .ds-file-perm-tag.is-noaccess { color: var(--flame); border-color: var(--flame); }
1986
2093
  .ds-247420 .ds-file-cell-open {
1987
2094
  display: flex; flex-direction: column; align-items: stretch; gap: var(--space-1);
1988
2095
  width: 100%; padding: var(--space-1); margin: 0;
1989
2096
  background: none; border: none; cursor: pointer; color: var(--fg);
1990
2097
  }
1991
2098
  .ds-247420 .ds-file-cell-open[disabled] { cursor: default; }
1992
- .ds-247420 .ds-file-cell-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-2); }
2099
+ .ds-247420 .ds-file-cell-open:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; border-radius: var(--r-2); }
1993
2100
  .ds-247420 .ds-file-cell-media {
1994
2101
  display: flex; align-items: center; justify-content: center;
1995
2102
  width: 100%; aspect-ratio: 4 / 3;
@@ -2036,8 +2143,17 @@
2036
2143
 
2037
2144
  /* Full-width files stack: the stage's space-3 vertical beat without its
2038
2145
  920px cap/auto-margins, so the roots / toolbar / bulkbar / uploads / grid
2039
- bands keep one consistent rhythm instead of touching edge-to-edge. */
2040
- .ds-247420 .ds-files-stack { display: flex; flex-direction: column; gap: var(--space-3); min-height: 0; }
2146
+ bands keep one consistent rhythm instead of touching edge-to-edge. Carries
2147
+ the same side/bottom padding as .ds-file-stage (top collapses the same way
2148
+ when mounted directly under .app-main, which already supplies top padding)
2149
+ so switching a consumer from the capped stage to this full-width stack is a
2150
+ pure width change, not a spacing regression. */
2151
+ .ds-247420 .ds-files-stack {
2152
+ display: flex; flex-direction: column; gap: var(--space-3); min-height: 0;
2153
+ padding: 0 var(--space-3) var(--space-4);
2154
+ }
2155
+ .ds-247420 .app-main > div > .ds-files-stack,
2156
+ .ds-247420 .app-main .ds-files-stack { padding-top: 0; }
2041
2157
 
2042
2158
  /* Breadcrumb path */
2043
2159
  .ds-247420 .ds-crumb-path {
@@ -2049,6 +2165,10 @@
2049
2165
  padding: 4px 8px; border-radius: var(--r-1);
2050
2166
  color: var(--fg-3); font-family: inherit; font-size: var(--fs-sm);
2051
2167
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
2168
+ /* A single long unbroken segment (hash-named dir) must never force the
2169
+ whole path past the viewport. */
2170
+ max-width: min(40vw, 220px);
2171
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
2052
2172
  }
2053
2173
  .ds-247420 .ds-crumb-seg:hover { background: var(--bg-2); color: var(--fg); }
2054
2174
  .ds-247420 .ds-crumb-seg.leaf { color: var(--fg); font-weight: 600; }
@@ -2074,6 +2194,15 @@
2074
2194
  font-size: var(--fs-sm); color: var(--fg-3);
2075
2195
  }
2076
2196
  .ds-247420 .ds-page-header-dense .ds-page-header-right { flex: 0 0 auto; margin-left: auto; }
2197
+ /* Below ~480px the single-line ellipsis truncates the majority of the lede
2198
+ text with no way to recover it (no title attr, no expand) - let the row
2199
+ wrap and the lede break onto its own line instead of clipping. */
2200
+ @media (max-width: 480px) {
2201
+ .ds-247420 .ds-page-header-dense-row { flex-wrap: wrap; }
2202
+ .ds-247420 .ds-page-header-dense-lede {
2203
+ flex-basis: 100%; overflow: visible; text-overflow: clip; white-space: normal;
2204
+ }
2205
+ }
2077
2206
  .ds-247420 .ds-file-toolbar-left,
2078
2207
  .ds-247420 .ds-file-toolbar-right {
2079
2208
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
@@ -2145,6 +2274,14 @@
2145
2274
  border-radius: var(--r-3);
2146
2275
  }
2147
2276
  .ds-247420 .ds-dropzone--wrap.dragover { animation: none; }
2277
+ /* Touch devices can never fire dragover — keep the pick-files affordance
2278
+ visible as a compact static row so upload stays reachable in wrap mode. */
2279
+ @media (hover: none) and (pointer: coarse) {
2280
+ .ds-247420 .ds-dropzone--wrap > .ds-dropzone-inner {
2281
+ display: flex; position: static; padding: var(--space-2);
2282
+ outline: none; background: transparent;
2283
+ }
2284
+ }
2148
2285
 
2149
2286
  /* Upload progress */
2150
2287
  .ds-247420 .ds-upload-progress { display: flex; flex-direction: column; gap: 6px; }
@@ -2173,7 +2310,12 @@
2173
2310
  .ds-247420 .ds-upload-item.error .ds-upload-fill { background: var(--warn); }
2174
2311
  .ds-247420 .ds-upload-item.error .ds-upload-pct { color: var(--warn); }
2175
2312
  /* Per-row upload recovery actions (replace / dismiss) — error rows are not dead ends. */
2176
- .ds-247420 .ds-upload-item { grid-template-columns: minmax(0, 1fr) 120px 44px auto; }
2313
+ .ds-247420 .ds-upload-item { grid-template-columns: minmax(0, 1fr) minmax(60px, 120px) 44px auto; }
2314
+ @media (max-width: 480px) {
2315
+ .ds-247420 .ds-upload-item { grid-template-columns: minmax(0, 1fr) 44px; }
2316
+ .ds-247420 .ds-upload-bar { grid-column: 1 / -1; order: 3; }
2317
+ .ds-247420 .ds-upload-actions { grid-column: 1 / -1; justify-content: flex-end; }
2318
+ }
2177
2319
  .ds-247420 .ds-upload-actions { display: inline-flex; gap: var(--space-1); justify-content: flex-end; }
2178
2320
  .ds-247420 .ds-upload-act {
2179
2321
  padding: 2px 10px; min-height: 24px; cursor: pointer;
@@ -2181,9 +2323,14 @@
2181
2323
  color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-micro);
2182
2324
  }
2183
2325
  .ds-247420 .ds-upload-act:hover { background: var(--bg-3); color: var(--fg); }
2184
- .ds-247420 .ds-upload-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
2326
+ .ds-247420 .ds-upload-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2185
2327
  @media (hover: none), (pointer: coarse) {
2186
2328
  .ds-247420 .ds-upload-act { min-height: 44px; min-width: 44px; }
2329
+ /* 44px floor for file controls on ANY touch device, not only narrow ones
2330
+ (the width-based mobile block misses wide touch tablets). */
2331
+ .ds-247420 .ds-file-act, .ds-247420 .ds-file-sort-btn, .ds-247420 .ds-crumb-seg, .ds-247420 .ds-file-filter-input { min-height: 44px; }
2332
+ .ds-247420 .ds-file-act { min-width: 44px; }
2333
+ .ds-247420 .ds-file-check, .ds-247420 .ds-file-selectall, .ds-247420 .ds-density-btn { min-height: 44px; min-width: 44px; }
2187
2334
  }
2188
2335
 
2189
2336
  /* Empty state */
@@ -2199,7 +2346,11 @@
2199
2346
  .ds-247420 .ds-modal-backdrop {
2200
2347
  position: fixed; inset: 0; z-index: var(--z-modal, 800);
2201
2348
  display: flex; align-items: center; justify-content: center;
2202
- padding: var(--space-3);
2349
+ /* Notch/home-indicator safe: near-fullscreen modals must not slide under. */
2350
+ padding: max(var(--space-3), env(safe-area-inset-top))
2351
+ max(var(--space-3), env(safe-area-inset-right))
2352
+ max(var(--space-3), env(safe-area-inset-bottom))
2353
+ max(var(--space-3), env(safe-area-inset-left));
2203
2354
  background: color-mix(in oklab, var(--ink) 55%, transparent);
2204
2355
  backdrop-filter: blur(3px);
2205
2356
  }
@@ -2209,7 +2360,9 @@
2209
2360
  @keyframes ds-modal-fade { from { opacity: 0; } to { opacity: 1; } }
2210
2361
  .ds-247420 .ds-modal {
2211
2362
  display: flex; flex-direction: column;
2212
- width: 100%; max-width: 460px; max-height: calc(100vh - 2 * var(--space-4));
2363
+ width: 100%; max-width: 460px;
2364
+ max-height: calc(100vh - 2 * var(--space-4));
2365
+ max-height: calc(100dvh - 2 * var(--space-4));
2213
2366
  background: var(--bg); color: var(--fg);
2214
2367
  border: var(--bw-hair) solid var(--rule);
2215
2368
  border-radius: var(--r-3); box-shadow: var(--shadow-3);
@@ -2241,7 +2394,11 @@
2241
2394
  border-radius: var(--r-2); color: var(--fg);
2242
2395
  font-family: inherit; font-size: var(--fs-sm);
2243
2396
  }
2244
- .ds-247420 .ds-modal-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
2397
+ .ds-247420 .ds-modal-input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
2398
+ /* iOS auto-zooms inputs under 16px on focus, breaking the modal layout. */
2399
+ @media (hover: none), (pointer: coarse) {
2400
+ .ds-247420 .ds-modal-input { font-size: 16px; min-height: 44px; }
2401
+ }
2245
2402
  /* In-body modal error (role=alert): mutation failures (409/403) surface INSIDE
2246
2403
  the dialog, not behind the fixed overlay. */
2247
2404
  .ds-247420 .ds-modal-error {
@@ -2265,10 +2422,12 @@
2265
2422
  .ds-247420 .ds-preview-name {
2266
2423
  font-weight: 600; font-size: var(--fs-body);
2267
2424
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
2425
+ flex: 1 1 auto;
2268
2426
  }
2269
2427
  .ds-247420 .ds-preview-meta {
2270
2428
  font-family: var(--ff-mono); font-size: var(--fs-xs);
2271
2429
  color: var(--fg-3); white-space: nowrap;
2430
+ flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
2272
2431
  }
2273
2432
  .ds-247420 .ds-preview-actions { display: inline-flex; gap: 2px; margin-left: auto; }
2274
2433
  .ds-247420 .ds-preview-body {
@@ -2277,7 +2436,9 @@
2277
2436
  display: flex; flex-direction: column;
2278
2437
  }
2279
2438
  .ds-247420 .ds-preview-media {
2280
- max-width: 100%; max-height: 70vh; margin: 0 auto;
2439
+ max-width: 100%;
2440
+ max-height: 70vh; max-height: 70dvh;
2441
+ margin: 0 auto;
2281
2442
  border-radius: var(--r-2); object-fit: contain;
2282
2443
  }
2283
2444
  .ds-247420 .ds-preview-audio { width: 100%; }
@@ -2323,10 +2484,22 @@
2323
2484
 
2324
2485
  /* Mobile — modals go near-fullscreen, preview media shrinks. */
2325
2486
  @media (max-width: 560px) {
2326
- .ds-247420 .ds-modal { max-width: 100%; max-height: calc(100vh - 2 * var(--space-3)); }
2327
- .ds-247420 .ds-modal-preview { width: 100%; height: calc(100vh - 2 * var(--space-3)); max-height: none; }
2328
- .ds-247420 .ds-preview-media { max-height: 50vh; }
2487
+ .ds-247420 .ds-modal {
2488
+ max-width: 100%;
2489
+ max-height: calc(100vh - 2 * var(--space-3));
2490
+ max-height: calc(100dvh - 2 * var(--space-3));
2491
+ }
2492
+ .ds-247420 .ds-modal-preview {
2493
+ width: 100%; max-height: none;
2494
+ height: calc(100vh - 2 * var(--space-3));
2495
+ height: calc(100dvh - 2 * var(--space-3));
2496
+ }
2497
+ .ds-247420 .ds-preview-media { max-height: 50vh; max-height: 50dvh; }
2329
2498
  .ds-247420 .ds-file-stage { padding: var(--space-3) var(--space-2); }
2499
+ /* Preview head: let it wrap and drop the nowrap meta (duplicated in body)
2500
+ so the close button can never be pushed past the modal edge. */
2501
+ .ds-247420 .ds-preview-head { flex-wrap: wrap; row-gap: 4px; }
2502
+ .ds-247420 .ds-preview-meta { display: none; }
2330
2503
  }
2331
2504
 
2332
2505
  /* -- File browser UX affordances ---------------------------- */
@@ -2385,7 +2558,7 @@
2385
2558
  .ds-247420 .ds-kbd-sep { color: var(--fg-3); font-size: var(--fs-micro); padding: 0 2px; }
2386
2559
  .ds-247420 .ds-kbd {
2387
2560
  display: inline-block; min-width: 0;
2388
- padding: 2px 7px; border-radius: 6px;
2561
+ padding: 2px 7px; border-radius: var(--r-0);
2389
2562
  background: var(--bg); border: var(--bw-hair) solid var(--rule);
2390
2563
  border-bottom-width: 2px;
2391
2564
  font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-2);
@@ -2407,7 +2580,7 @@
2407
2580
  transition: color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
2408
2581
  }
2409
2582
  .ds-247420 .ds-segmented .ds-seg-btn:hover { color: var(--fg); }
2410
- .ds-247420 .ds-segmented .ds-seg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
2583
+ .ds-247420 .ds-segmented .ds-seg-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
2411
2584
  .ds-247420 .ds-segmented .ds-seg-btn.is-on {
2412
2585
  background: var(--bg); color: var(--fg);
2413
2586
  box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule);
@@ -2461,7 +2634,7 @@
2461
2634
  .ds-247420 .chat-thread { scroll-behavior: smooth; }
2462
2635
  }
2463
2636
  .ds-247420 .chat-thread::-webkit-scrollbar { width: 8px; }
2464
- .ds-247420 .chat-thread::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: 4px; }
2637
+ .ds-247420 .chat-thread::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: var(--r-0); }
2465
2638
  .ds-247420 .chat-empty {
2466
2639
  margin: auto;
2467
2640
  text-align: center;
@@ -2475,7 +2648,7 @@
2475
2648
  .ds-247420 .chat-msg { display: flex; gap: 12px; align-items: flex-start; padding: 6px 0; position: relative; min-width: 0; }
2476
2649
  .ds-247420 .chat-msg.you { flex-direction: row-reverse; }
2477
2650
  .ds-247420 .chat-msg.you .chat-stack { align-items: flex-end; }
2478
- .ds-247420 .chat-msg:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); padding: 6px 0; margin: 0; border-radius: 8px; transition: background var(--dur-base) var(--ease); }
2651
+ .ds-247420 .chat-msg:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); padding: 6px 0; margin: 0; border-radius: var(--r-0); transition: background var(--dur-base) var(--ease); }
2479
2652
 
2480
2653
  .ds-247420 .chat-avatar {
2481
2654
  width: 36px; height: 36px; flex-shrink: 0;
@@ -2521,7 +2694,7 @@
2521
2694
  .ds-247420 .chat-bubble code {
2522
2695
  font-family: var(--ff-mono); font-size: 0.92em;
2523
2696
  background: color-mix(in oklab, var(--fg) 10%, transparent);
2524
- padding: 1px 6px; border-radius: 4px;
2697
+ padding: 1px 6px; border-radius: var(--r-0);
2525
2698
  }
2526
2699
  .ds-247420 .chat-msg.you .chat-bubble code { background: color-mix(in oklab, var(--fg) 10%, transparent); }
2527
2700
  .ds-247420 .chat-bubble a {
@@ -2632,7 +2805,7 @@
2632
2805
  .ds-247420 .chat-msg.you .chat-image,
2633
2806
  .ds-247420 .chat-msg .chat-image,
2634
2807
  .ds-247420 .chat-image {
2635
- display: inline-block; border-radius: 12px; overflow: hidden;
2808
+ display: inline-block; border-radius: var(--r-1); overflow: hidden;
2636
2809
  max-width: min(100%, 480px); background: var(--bg-2);
2637
2810
  text-decoration: none; color: var(--fg);
2638
2811
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
@@ -2651,7 +2824,7 @@
2651
2824
  .ds-247420 .chat-file {
2652
2825
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
2653
2826
  background: var(--bg-2); border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
2654
- border-radius: 12px; text-decoration: none; color: var(--fg);
2827
+ border-radius: var(--r-1); text-decoration: none; color: var(--fg);
2655
2828
  max-width: min(100%, 360px);
2656
2829
  transition: background var(--dur-snap, .15s) var(--ease, ease), border-color var(--dur-snap, .15s) var(--ease, ease);
2657
2830
  }
@@ -2660,7 +2833,7 @@
2660
2833
  font-size: 22px; width: 36px; height: 36px;
2661
2834
  display: inline-flex; align-items: center; justify-content: center;
2662
2835
  background: color-mix(in oklab, var(--accent) 18%, transparent);
2663
- color: var(--accent-ink); border-radius: 8px; flex-shrink: 0; font-family: var(--ff-mono);
2836
+ color: var(--accent-ink); border-radius: var(--r-0); flex-shrink: 0; font-family: var(--ff-mono);
2664
2837
  }
2665
2838
  .ds-247420 .chat-file > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
2666
2839
  .ds-247420 .chat-file .name {
@@ -2678,7 +2851,7 @@
2678
2851
  background: var(--bg-2);
2679
2852
  color: var(--fg);
2680
2853
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
2681
- border-radius: 12px; overflow: hidden; max-width: min(100%, 480px);
2854
+ border-radius: var(--r-1); overflow: hidden; max-width: min(100%, 480px);
2682
2855
  transition: box-shadow 0.12s ease, border-color 0.12s ease;
2683
2856
  }
2684
2857
  .ds-247420 .chat-msg:hover .chat-pdf { border-color: color-mix(in oklab, var(--accent) 30%, transparent); }
@@ -2701,7 +2874,7 @@
2701
2874
  display: grid; grid-template-columns: 80px 1fr; gap: 12px; padding: 10px;
2702
2875
  background: var(--bg-2);
2703
2876
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
2704
- border-radius: 12px; text-decoration: none; color: var(--fg);
2877
+ border-radius: var(--r-1); text-decoration: none; color: var(--fg);
2705
2878
  max-width: min(100%, 480px);
2706
2879
  transition: background var(--dur-snap, .15s) var(--ease, ease), border-color var(--dur-snap, .15s) var(--ease, ease), box-shadow 0.15s ease;
2707
2880
  }
@@ -2712,7 +2885,7 @@
2712
2885
  }
2713
2886
  .ds-247420 .chat-link:not(:has(.thumb)):not(:has(img)) { grid-template-columns: 1fr; }
2714
2887
  .ds-247420 .chat-link .thumb,
2715
- .ds-247420 .chat-link img.thumb { width: 80px; height: 80px; border-radius: 8px; object-fit: cover; background: var(--bg-3) center/cover no-repeat; }
2888
+ .ds-247420 .chat-link img.thumb { width: 80px; height: 80px; border-radius: var(--r-0); object-fit: cover; background: var(--bg-3) center/cover no-repeat; }
2716
2889
  .ds-247420 .chat-link .meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
2717
2890
  .ds-247420 .chat-link .host { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); text-transform: lowercase; }
2718
2891
  .ds-247420 .chat-link .title { font-weight: 600; font-size: var(--fs-sm); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
@@ -2736,7 +2909,7 @@
2736
2909
  display: inline-flex; align-items: center; gap: 4px;
2737
2910
  padding: 2px 8px; background: var(--bg-2);
2738
2911
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
2739
- border-radius: 999px; font-size: var(--fs-xs);
2912
+ border-radius: var(--r-pill); font-size: var(--fs-xs);
2740
2913
  cursor: pointer; user-select: none;
2741
2914
  transition: background var(--dur-snap, .12s) var(--ease, ease), border-color var(--dur-snap, .12s) var(--ease, ease), transform 0.12s ease;
2742
2915
  position: relative;
@@ -2857,7 +3030,7 @@
2857
3030
  .ds-247420 .chat-composer .send:active { filter: brightness(0.94); }
2858
3031
  .ds-247420 .chat-composer .send:focus-visible,
2859
3032
  .ds-247420 .composer-btn:focus-visible {
2860
- outline: 2px solid var(--accent);
3033
+ outline: 2px solid var(--accent-ink);
2861
3034
  outline-offset: 2px;
2862
3035
  }
2863
3036
  .ds-247420 .chat-composer .send:disabled {
@@ -2943,10 +3116,21 @@
2943
3116
  .ds-247420 .chat-composer textarea { padding: 10px 12px; }
2944
3117
  }
2945
3118
 
2946
- /* --- landscape orientation: reduce vertical space for composer --- */
3119
+ /* --- landscape orientation: reduce vertical space for chrome + composer --- */
2947
3120
  @media (max-height: 500px) and (orientation: landscape) {
2948
- .ds-247420 .chat-composer { padding: 6px 0; }
2949
- .ds-247420 .chat-composer textarea { min-height: 44px; max-height: 120px; }
3121
+ /* Keep horizontal padding: 0 put the textarea/focus ring flush on the edge. */
3122
+ .ds-247420 .chat-composer { padding: 6px var(--space-2); }
3123
+ .ds-247420 .chat-composer textarea { min-height: 36px; max-height: 96px; }
3124
+ .ds-247420 .chat-composer .chat-composer-hint,
3125
+ .ds-247420 .chat-composer .chat-composer-context { display: none; }
3126
+ /* Compact the shell chrome: ~114px of topbar+crumb+status is a third of a
3127
+ 360px-tall landscape fold. */
3128
+ .ds-247420 { --app-topbar-h: 40px; --app-crumb-h: 24px; }
3129
+ .ds-247420 .app-chrome { padding: 4px var(--pad-x); }
3130
+ .ds-247420 .app-status { display: none; }
3131
+ .ds-247420 .ws-crumb { min-height: 32px; }
3132
+ .ds-247420 .ds-hero { padding: var(--space-4) 0 var(--space-3); }
3133
+ .ds-247420 .ds-hero-title { font-size: clamp(28px, 6cqi, 56px); }
2950
3134
  }
2951
3135
 
2952
3136
  /* ============================================================
@@ -2958,8 +3142,12 @@
2958
3142
  Component States — Disabled, Loading, Error, Success
2959
3143
  -------------------------------------------------------------- */
2960
3144
 
2961
- /* Disabled state for all interactive elements */
2962
- .ds-247420 .btn:disabled, .ds-247420 .btn-primary:disabled, .ds-247420 .btn-ghost:disabled, .ds-247420 button:disabled, .ds-247420[disabled] {
3145
+ /* Disabled state for all interactive elements. The `.is-disabled` class
3146
+ variants cover Btn()'s anchor-rendered case (shell.js) an <a> has no
3147
+ :disabled pseudo-class, so a disabled link-styled button relies entirely
3148
+ on this class selector for its visual treatment (aria-disabled + tabindex
3149
+ are set in JS; this is the paired CSS half). */
3150
+ .ds-247420 .btn:disabled, .ds-247420 .btn-primary:disabled, .ds-247420 .btn-ghost:disabled, .ds-247420 .btn.is-disabled, .ds-247420 .btn-primary.is-disabled, .ds-247420 .btn-ghost.is-disabled, .ds-247420 button:disabled, .ds-247420[disabled] {
2963
3151
  opacity: 0.6;
2964
3152
  cursor: not-allowed;
2965
3153
  pointer-events: none;
@@ -3289,7 +3477,7 @@
3289
3477
 
3290
3478
  /* Base focus-visible: 2px ring + 2px offset clears dark bg-3 surfaces (WCAG 1.4.11) */
3291
3479
  .ds-247420 :focus-visible {
3292
- outline: 2px solid var(--accent);
3480
+ outline: 2px solid var(--accent-ink);
3293
3481
  outline-offset: 2px;
3294
3482
  }
3295
3483
 
@@ -3299,7 +3487,7 @@
3299
3487
  .ds-247420[role="tab"]:focus-visible,
3300
3488
  .ds-247420 .row:focus-visible,
3301
3489
  .ds-247420 .row[tabindex]:focus-visible {
3302
- outline: 2px solid var(--accent);
3490
+ outline: 2px solid var(--accent-ink);
3303
3491
  outline-offset: 2px;
3304
3492
  }
3305
3493
 
@@ -3370,6 +3558,15 @@
3370
3558
  }
3371
3559
  }
3372
3560
 
3561
+ /* Touch floor also for coarse-pointer devices that report hover (hybrid
3562
+ laptops/tablets with mice) — the block above requires hover:none too. */
3563
+ @media (pointer: coarse) {
3564
+ .ds-247420 .ds-icon-btn, .ds-247420 .ds-icon-btn-xs, .ds-247420 .ds-icon-btn-sm, .ds-247420 .ds-icon-btn-base {
3565
+ min-width: 44px; min-height: 44px;
3566
+ }
3567
+ .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost, .ds-247420 .app-topbar nav a, .ds-247420 .app-side a { min-height: 44px; }
3568
+ }
3569
+
3373
3570
  /* ------------------------------------------------------------
3374
3571
  Theme Transition Smoothness
3375
3572
  -------------------------------------------------------------- */
@@ -3601,16 +3798,24 @@
3601
3798
  .ds-247420 .app-body.no-side { grid-template-columns: 1fr !important; }
3602
3799
  .ds-247420 .app-side-shell {
3603
3800
  position: absolute;
3604
- left: 0; top: var(--app-topbar-h);
3605
- height: calc(100% - var(--app-topbar-h) - var(--app-status-h));
3801
+ /* Full-height overlay drawer: the merged .app-chrome wraps and its real
3802
+ height drifts from --app-topbar-h, so anchoring below it misplaces the
3803
+ drawer. Overlay the chrome instead (z above --z-header), like ws drawers. */
3804
+ left: 0; top: 0;
3805
+ height: 100%;
3606
3806
  width: 280px; max-width: 80%;
3607
3807
  transform: translateX(-100%);
3608
3808
  transition: transform var(--dur-base, 240ms) var(--ease, ease);
3609
- z-index: 50;
3809
+ /* Above the sticky chrome (z-header): scrim > chrome > content budget. */
3810
+ z-index: calc(var(--z-header, 100) + 2);
3610
3811
  background: var(--bg);
3611
3812
  border-right: 1px solid color-mix(in oklab, var(--fg) 8%, transparent);
3612
3813
  overflow-y: auto;
3814
+ overscroll-behavior: contain;
3613
3815
  }
3816
+ /* Lock the content scroller while the drawer is open so touch pans don't
3817
+ scroll the page behind the scrim. */
3818
+ .ds-247420 .app-body.side-open .app-main { overflow: hidden; }
3614
3819
  .ds-247420 .app-side-shell.open,
3615
3820
  .ds-247420 .app-side.open,
3616
3821
  .ds-247420 .app-body.side-open .app-side-shell { transform: translateX(0); }
@@ -3643,7 +3848,8 @@
3643
3848
  display: none;
3644
3849
  position: absolute; inset: 0;
3645
3850
  background: color-mix(in oklab, var(--bg) 60%, transparent);
3646
- z-index: 49;
3851
+ /* Above the sticky chrome so nav behind an open drawer is not clickable. */
3852
+ z-index: calc(var(--z-header, 100) + 1);
3647
3853
  }
3648
3854
  @container (max-width: 900px) {
3649
3855
  .ds-247420 .app-body.side-open .app-side-scrim { display: block; }
@@ -3655,7 +3861,9 @@
3655
3861
  .ds-247420 .app-side-toggle {
3656
3862
  display: none;
3657
3863
  position: absolute; top: calc((var(--app-topbar-h) - 44px) / 2); left: 10px;
3658
- z-index: 51;
3864
+ /* Above the sticky topbar/chrome (z-header) and the drawer/scrim so the
3865
+ translucent blurred chrome never paints over or intercepts the toggle. */
3866
+ z-index: calc(var(--z-header, 100) + 3);
3659
3867
  /* 44x44 minimum hit area (WCAG 2.5.5 / Apple HIG) - 36px is below the
3660
3868
  reliable-tap threshold on touch. */
3661
3869
  width: 44px; height: 44px;
@@ -3666,7 +3874,7 @@
3666
3874
  border-radius: var(--r-1, 6px);
3667
3875
  cursor: pointer;
3668
3876
  }
3669
- .ds-247420 .app-side-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
3877
+ .ds-247420 .app-side-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
3670
3878
  @container (max-width: 900px) {
3671
3879
  .ds-247420 .app-side-toggle { display: inline-flex; }
3672
3880
  .ds-247420 .app-topbar .brand { margin-left: 44px; }
@@ -3707,6 +3915,8 @@
3707
3915
  .ds-247420 .app-topbar nav,
3708
3916
  .ds-247420 .app-topbar > :last-child { display: none; }
3709
3917
  .ds-247420 .brand { font-size: var(--fs-tiny); }
3918
+ /* Slightly narrower drawer on tiny phones; max-width:80% remains the guard. */
3919
+ .ds-247420 .app-side-shell { width: 260px; }
3710
3920
  }
3711
3921
 
3712
3922
  /* ----------------------------------------------------------------------------
@@ -3754,7 +3964,7 @@
3754
3964
  .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; }
3755
3965
  .ds-247420 .ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background: transparent; transition: background var(--dur-snap) var(--ease); }
3756
3966
  .ds-247420 .ws-resizer:hover::after, .ds-247420 .ws-resizer:focus-visible::after { background: var(--accent); }
3757
- .ds-247420 .ws-resizer:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
3967
+ .ds-247420 .ws-resizer:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
3758
3968
  .ds-247420 .ws-resizer.ws-resizer-rail { grid-column: 1; }
3759
3969
  .ds-247420 .ws-resizer.ws-resizer-sessions { grid-column: 2; }
3760
3970
  .ds-247420 .ws-resizer.ws-resizer-pane { grid-column: 3; justify-self: end; }
@@ -3780,6 +3990,11 @@
3780
3990
  @media (prefers-reduced-motion: no-preference) {
3781
3991
  .ds-247420 .ws-shell { transition: grid-template-columns var(--dur-base) var(--ease); }
3782
3992
  }
3993
+ /* Ultrawide: cap the shell so the 1fr content track doesn't stretch to
3994
+ unreadable measures while the fixed side columns pin to their clamps. */
3995
+ @media (min-width: 1920px) {
3996
+ .ds-247420 .ws-shell { max-width: 1920px; margin-inline: auto; }
3997
+ }
3783
3998
 
3784
3999
  /* Rail (left nav) */
3785
4000
  .ds-247420 .ws-rail {
@@ -3801,7 +4016,7 @@
3801
4016
  border-radius: var(--r-1); cursor: pointer;
3802
4017
  }
3803
4018
  .ds-247420 .ws-rail-toggle:hover { background: var(--bg-3); color: var(--fg); }
3804
- .ds-247420 .ws-rail-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
4019
+ .ds-247420 .ws-rail-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
3805
4020
  .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); }
3806
4021
  .ds-247420 .ws-rail-head { display: flex; align-items: center; min-height: 36px; padding: 0 var(--space-2); }
3807
4022
  .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; }
@@ -3814,8 +4029,8 @@
3814
4029
  min-height: 40px; white-space: nowrap; overflow: hidden;
3815
4030
  }
3816
4031
  .ds-247420 .ws-rail-action:hover { filter: brightness(1.08); }
3817
- .ds-247420 .ws-rail-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
3818
- .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; }
4032
+ .ds-247420 .ws-rail-action:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4033
+ .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; }
3819
4034
  .ds-247420 .ws-rail-item {
3820
4035
  display: flex; align-items: center; gap: var(--space-2);
3821
4036
  width: 100%; padding: var(--space-2); min-height: 44px;
@@ -3824,7 +4039,7 @@
3824
4039
  font-family: var(--ff-body); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden;
3825
4040
  }
3826
4041
  .ds-247420 .ws-rail-item:hover { background: var(--bg-3); color: var(--fg); }
3827
- .ds-247420 .ws-rail-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
4042
+ .ds-247420 .ws-rail-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
3828
4043
  .ds-247420 .ws-rail-item.active { background: var(--accent-tint); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
3829
4044
  .ds-247420 .ws-rail-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
3830
4045
  .ds-247420 .ws-rail-item-count { font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3); }
@@ -3878,6 +4093,7 @@
3878
4093
  min-height: 0; display: flex; flex-direction: column;
3879
4094
  background: var(--bg-2); border-left: var(--bw-hair) solid var(--bg-3);
3880
4095
  overflow: hidden; transition: width var(--dur-base) var(--ease);
4096
+ overscroll-behavior: contain;
3881
4097
  }
3882
4098
  .ds-247420 .ws-pane-collapsed .ws-pane { width: 0; border-left: none; }
3883
4099
  .ds-247420 .ws-pane-collapsed .ws-pane > * { display: none; }
@@ -3896,7 +4112,7 @@
3896
4112
  /* Desktop-only chrome toggle (sessions collapse): inverse of the mobile drawer-toggle. */
3897
4113
  .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); }
3898
4114
  .ds-247420 .ws-desktop-toggle:hover { background: var(--bg-2); color: var(--fg); }
3899
- .ds-247420 .ws-desktop-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
4115
+ .ds-247420 .ws-desktop-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
3900
4116
  @media (max-width: 900px) { .ds-247420 .ws-desktop-toggle { display: none; } }
3901
4117
  /* The pane collapse toggle is meaningless once the pane TRACK is dropped (the
3902
4118
  pane becomes a mobile overlay drawer at <=1480px, reached via its own
@@ -3962,12 +4178,19 @@
3962
4178
  }
3963
4179
  .ds-247420 .ws-sessions {
3964
4180
  position: fixed; inset: 0 auto 0 0;
3965
- width: min(var(--ws-sessions-w), 80vw);
4181
+ /* Immune to the desktop collapse var (--ws-sessions-w:0px persisted from
4182
+ a desktop session would open an invisible 0-width drawer). */
4183
+ width: min(max(var(--ws-sessions-w), 280px), 80vw);
3966
4184
  z-index: 42; transform: translateX(-110%);
3967
4185
  transition: transform var(--dur-base) var(--ease);
3968
4186
  border-right: var(--bw-hair) solid var(--bg-3);
4187
+ overscroll-behavior: contain;
3969
4188
  }
3970
4189
  .ds-247420 .ws-shell.ws-sessions-open .ws-sessions { transform: translateX(0); }
4190
+ /* Drawer mode ignores the desktop collapsed state: children stay rendered
4191
+ and the border returns, so a persisted collapse can't blank the drawer. */
4192
+ .ds-247420 .ws-shell.ws-sessions-collapsed .ws-sessions > * { display: revert; }
4193
+ .ds-247420 .ws-shell.ws-sessions-collapsed .ws-sessions { border-right: var(--bw-hair) solid var(--bg-3); }
3971
4194
  .ds-247420 .ws-sessions-drawer-toggle { display: inline-flex; }
3972
4195
  }
3973
4196
 
@@ -4013,7 +4236,7 @@
4013
4236
  .ds-247420 .ws-crumb .app-crumb .crumb-right { margin-left: 0; flex-wrap: wrap; min-width: 0; display: inline-flex; }
4014
4237
  }
4015
4238
  .ds-247420 .ws-drawer-toggle:hover { background: var(--bg-2); color: var(--fg); }
4016
- .ds-247420 .ws-drawer-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
4239
+ .ds-247420 .ws-drawer-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4017
4240
 
4018
4241
  @media (prefers-reduced-motion: reduce) {
4019
4242
  .ds-247420 .ws-shell, .ds-247420 .ws-rail, .ds-247420 .ws-pane, .ds-247420 .ws-sessions, .ds-247420 .ws-scrim { transition: none; }
@@ -4025,7 +4248,7 @@
4025
4248
  ============================================================ */
4026
4249
 
4027
4250
  /* Highlighted match inside a Row title (Row `highlight` prop). */
4028
- .ds-247420 .ds-hl { background: color-mix(in oklab, var(--accent) 25%, transparent); color: inherit; border-radius: 2px; }
4251
+ .ds-247420 .ds-hl { background: color-mix(in oklab, var(--accent) 25%, transparent); color: inherit; border-radius: var(--r-hair); }
4029
4252
 
4030
4253
  /* Action strip rendered inside an EXPANDED Row (Row `actions` prop). The
4031
4254
  buttons stop propagation so they never fire the row onClick. */
@@ -4038,20 +4261,20 @@
4038
4261
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
4039
4262
  }
4040
4263
  .ds-247420 .row-act:hover { background: var(--bg-3); color: var(--fg); }
4041
- .ds-247420 .row-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
4264
+ .ds-247420 .row-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4042
4265
 
4043
4266
  /* FilterPills - a group of pill toggle buttons (aria-pressed). */
4044
4267
  .ds-247420 .ds-filter-pills { display: flex; flex-wrap: wrap; gap: var(--space-2); }
4045
4268
  .ds-247420 .ds-filter-pill {
4046
4269
  display: inline-flex; align-items: center; justify-content: center;
4047
4270
  padding: 4px 12px; min-height: 28px;
4048
- background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: 999px;
4271
+ background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-pill);
4049
4272
  color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-tiny); cursor: pointer;
4050
4273
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
4051
4274
  }
4052
4275
  .ds-247420 .ds-filter-pill:hover { background: var(--bg-3); color: var(--fg); }
4053
4276
  .ds-247420 .ds-filter-pill.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
4054
- .ds-247420 .ds-filter-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
4277
+ .ds-247420 .ds-filter-pill:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4055
4278
 
4056
4279
  /* Touch floor for the new small controls. */
4057
4280
  @media (pointer: coarse) {
@@ -4061,7 +4284,7 @@
4061
4284
  /* Disabled file actions (read-only row / in-flight mutation) stay visible but inert. */
4062
4285
  .ds-247420 .ds-file-act:disabled { opacity: .45; cursor: default; }
4063
4286
  .ds-247420 .ds-file-act:disabled:hover { background: transparent; color: var(--fg-3); }
4064
- .ds-247420 .ds-file-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
4287
+ .ds-247420 .ds-file-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
4065
4288
 
4066
4289
  /* ============================================================
4067
4290
  Print — linearize WorkspaceShell so main content prints in full.
@@ -4077,6 +4300,509 @@
4077
4300
  .ds-247420 .ws-crumb,
4078
4301
  .ds-247420 .app-status { display: none; }
4079
4302
  .ds-247420 .ws-main { overflow: visible; height: auto; }
4303
+ /* AppShell: unpin the viewport-height frame so content flows across pages,
4304
+ and drop all chrome (it prints as page furniture otherwise). */
4305
+ .ds-247420 .app { height: auto; min-height: 0; overflow: visible; display: block; }
4306
+ .ds-247420 .app-body { display: block; }
4307
+ .ds-247420 .app-main { overflow: visible; height: auto; display: block; max-width: 100%; }
4308
+ .ds-247420 .app-topbar, .ds-247420 .app-chrome, .ds-247420 .app-crumb, .ds-247420 .app-side-shell, .ds-247420 .app-side-scrim, .ds-247420 .app-side-toggle, .ds-247420 .btn-fab, .ds-247420 .skip-link, .ds-247420 .ds-marquee { display: none; }
4309
+ /* Modals/preview: print the content, not a blurred overlay clipped to one page. */
4310
+ .ds-247420 .ds-modal-backdrop { position: static; background: none; backdrop-filter: none; padding: 0; }
4311
+ .ds-247420 .ds-modal, .ds-247420 .ds-modal-preview { max-width: 100%; max-height: none; box-shadow: none; }
4312
+ .ds-247420 .ds-modal-body, .ds-247420 .ds-preview-body, .ds-247420 .ds-preview-code, .ds-247420 .ds-preview-text { overflow: visible; }
4313
+ .ds-247420 .ds-modal-actions, .ds-247420 .ds-preview-actions { display: none; }
4314
+ /* Data-density: fixed-height log clips; bg-only tiles lose their boundary. */
4315
+ .ds-247420 .ds-live-log { height: auto; max-height: none; overflow: visible; }
4316
+ .ds-247420 .ds-stat, .ds-247420 .kpi-card { border: 1px solid var(--rule); }
4317
+ .ds-247420 .ds-session-row { break-inside: avoid; }
4318
+ }
4319
+
4320
+ /* ============================================================
4321
+ Data density — dense observability/dashboard primitives (ported from the
4322
+ gmsniff GUI). Components: PhaseWalk, TreeNode, BarRow, StatTile/StatsGrid,
4323
+ SubGrid, SessionRow, DevRow, LiveLog/LiveLogEntry. src/components/data-density.js.
4324
+ All colors derive from colors_and_type.css tokens — see lint-tokens.mjs.
4325
+ ============================================================ */
4326
+
4327
+ /* --danger-surface: semantic surface for a deviation/error callout background
4328
+ (gmsniff's #3a1a1a dark-red-tinted panel). Derived from --warn so it always
4329
+ reads as "danger" against the active theme instead of a baked literal. */
4330
+ .ds-247420 {
4331
+ --danger-surface: color-mix(in oklab, var(--warn) 14%, var(--bg));
4332
+ }
4333
+
4334
+ /* PhaseWalk */
4335
+ .ds-247420 .ds-phasewalk { display: inline-flex; gap: 2px; vertical-align: middle; }
4336
+ .ds-247420 .ds-phasewalk-seg {
4337
+ width: 18px; height: 10px; border-radius: var(--r-hair);
4338
+ background: var(--bg-3); position: relative;
4339
+ }
4340
+ .ds-247420 .ds-phasewalk-seg.is-reached { background: var(--success); }
4341
+ .ds-247420 .ds-phasewalk-seg.is-gap { background: var(--warn); }
4342
+ /* Standalone PhaseWalk reserves headroom for the labels instead of letting
4343
+ them escape upward and overlap the element above. */
4344
+ .ds-247420 .ds-phasewalk { padding-top: 15px; }
4345
+ .ds-247420 .ds-phasewalk-lbl {
4346
+ position: absolute; top: -15px; left: 0;
4347
+ font-size: var(--fs-micro); color: var(--fg-3); white-space: nowrap;
4348
+ }
4349
+ /* Inline in a single-line SessionRow the labels would overlap the row above —
4350
+ segments already carry title tooltips. */
4351
+ .ds-247420 .ds-session-row .ds-phasewalk { padding-top: 0; }
4352
+ .ds-247420 .ds-session-row .ds-phasewalk-lbl { display: none; }
4353
+
4354
+ /* TreeNode */
4355
+ .ds-247420 .ds-tree-node {
4356
+ padding: 5px 10px; border-left: var(--bw-rule) solid var(--bg-3);
4357
+ margin: 2px 0 2px 16px; font-size: var(--fs-tiny);
4358
+ min-width: 0; overflow-wrap: anywhere;
4359
+ }
4360
+ @media (max-width: 400px) {
4361
+ .ds-247420 .ds-tree-node { margin-left: 8px; padding-left: 8px; }
4362
+ }
4363
+ .ds-247420 .ds-tree-node.is-phase { border-color: var(--accent); background: var(--bg-3); font-weight: 600; }
4364
+ .ds-247420 .ds-tree-node.is-deviation { border-color: var(--warn); background: var(--danger-surface); color: var(--warn); }
4365
+ .ds-247420 .ds-tree-node.is-mutable-resolve { border-color: var(--success); }
4366
+ .ds-247420 .ds-tree-node.is-prd-add { border-color: var(--sun); }
4367
+ .ds-247420 .ds-tree-node-ts { margin-right: 8px; color: var(--fg-3); }
4368
+ .ds-247420 .ds-tree-node-pills { margin-left: 6px; }
4369
+ .ds-247420 .ds-tree-node-reason { margin-top: 2px; color: var(--fg-2); }
4370
+ .ds-247420 .ds-tree-node-deviation { margin-top: 2px; }
4371
+ .ds-247420 .ds-tree-node-residuals { margin-top: 2px; color: var(--fg-3); }
4372
+
4373
+ /* BarRow */
4374
+ .ds-247420 .ds-bar-row { display: flex; align-items: center; gap: 8px; margin: 3px 0; font-size: var(--fs-tiny); }
4375
+ .ds-247420 .ds-bar-row-label { width: 100px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4376
+ .ds-247420 .ds-bar-bg { flex: 1; min-width: 60px; background: var(--bg-3); border-radius: var(--r-hair); height: 6px; overflow: hidden; }
4377
+ .ds-247420 .ds-bar-fill { background: var(--accent); height: 100%; border-radius: var(--r-hair); }
4378
+ .ds-247420 .ds-bar-row-value { flex-shrink: 0; color: var(--fg-2); max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4379
+ @media (max-width: 400px) {
4380
+ .ds-247420 .ds-bar-row-label { width: 72px; }
4381
+ }
4382
+
4383
+ /* StatTile / StatsGrid */
4384
+ /* min(140px, 100%) keeps the grid from collapsing to 1 column early inside
4385
+ padded panels; the wrapper div stretches its tile to equal row height. */
4386
+ .ds-247420 .ds-stats-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); gap: var(--space-2); }
4387
+ .ds-247420 .ds-stats-grid > div { display: grid; }
4388
+ @media (max-width: 360px) {
4389
+ .ds-247420 .ds-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1); }
4390
+ }
4391
+ .ds-247420 .ds-stats-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
4392
+ .ds-247420 .ds-stat { min-width: 0; background: var(--bg-3); border-radius: var(--r-0); padding: 10px 12px; }
4393
+ .ds-247420 .ds-stat-val { font-size: clamp(18px, 5cqi, 22px); font-weight: 700; color: var(--accent-ink); overflow-wrap: anywhere; }
4394
+ .ds-247420 .ds-stat-val.rate-big { font-size: clamp(24px, 7cqi, 32px); color: var(--success); }
4395
+ .ds-247420 .ds-stat-val.err-rate { font-size: clamp(24px, 7cqi, 32px); color: var(--warn); }
4396
+ .ds-247420 .ds-stat-lbl { font-size: var(--fs-micro); color: var(--fg-3); margin-top: 2px; }
4397
+
4398
+ /* SubGrid */
4399
+ .ds-247420 .ds-sub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 6px; margin-top: 8px; }
4400
+ .ds-247420 .ds-sub-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
4401
+ .ds-247420 .ds-sub-btn {
4402
+ padding: 6px 10px; background: var(--bg-3); border: var(--bw-hair) solid var(--bg-3);
4403
+ border-radius: var(--r-0); font-size: var(--fs-tiny); cursor: pointer; color: var(--fg);
4404
+ text-align: left; font-family: var(--ff-body);
4405
+ }
4406
+ .ds-247420 .ds-sub-btn:hover { border-color: var(--accent); color: var(--accent-ink); }
4407
+ .ds-247420 .ds-sub-btn span { display: block; font-size: 18px; font-weight: 700; color: var(--accent-ink); }
4408
+
4409
+ /* SessionRow */
4410
+ .ds-247420 .ds-session-row {
4411
+ display: flex; align-items: center; gap: 8px; padding: 6px 10px;
4412
+ flex-wrap: wrap; min-width: 0;
4413
+ border-bottom: var(--bw-hair) solid var(--bg-3); cursor: pointer;
4414
+ }
4415
+ .ds-247420 .ds-session-row:hover { background: var(--bg-3); }
4416
+ .ds-247420 .ds-session-row-id {
4417
+ font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--accent-ink);
4418
+ flex: 0 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4419
+ }
4420
+ .ds-247420 .ds-session-row-counts {
4421
+ font-size: var(--fs-micro); color: var(--fg-3);
4422
+ flex: 1 1 200px; min-width: 0;
4423
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4424
+ }
4425
+ @media (max-width: 640px) {
4426
+ .ds-247420 .ds-session-row-span { flex-basis: 100%; }
4427
+ }
4428
+ .ds-247420 .ds-session-row-devcnt { color: var(--warn); font-weight: 600; }
4429
+ .ds-247420 .ds-session-row-span { font-size: var(--fs-micro); color: var(--fg-3); }
4430
+
4431
+ /* DevRow */
4432
+ .ds-247420 .ds-dev-row {
4433
+ background: var(--danger-surface); border-left: var(--bw-chunk) solid var(--warn);
4434
+ padding: 8px 12px; margin: 4px 0; border-radius: var(--r-hair); font-size: var(--fs-tiny);
4435
+ }
4436
+ .ds-247420 .ds-dev-row strong { color: var(--warn); }
4437
+
4438
+ /* LiveLog — natural height with a viewport-tracking cap (dvh follows mobile
4439
+ URL-bar chrome; min-height keeps short-landscape from going near-zero). */
4440
+ .ds-247420 .ds-live-log {
4441
+ height: auto;
4442
+ max-height: calc(100vh - 200px);
4443
+ max-height: calc(100dvh - 200px);
4444
+ min-height: 160px;
4445
+ overflow-y: auto; overflow-x: hidden;
4446
+ font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.5;
4447
+ }
4448
+ /* Embedded in a WM window the viewport calc is meaningless — fill the container. */
4449
+ .ds-247420 .fd-root .ds-live-log { height: 100%; max-height: none; min-height: 0; flex: 1 1 auto; }
4450
+ .ds-247420 .ds-live-log-empty { height: auto; min-height: 0; padding: var(--space-3); color: var(--fg-3); }
4451
+ .ds-247420 .ds-live-log-entry { padding: 2px 8px; border-bottom: var(--bw-hair) solid var(--bg-3); overflow-wrap: anywhere; }
4452
+ .ds-247420 .ds-live-log-entry:hover { background: var(--bg-3); }
4453
+ .ds-247420 .ds-live-log-ts { margin-right: 6px; color: var(--fg-3); }
4454
+ .ds-247420 .ds-live-log-subtag { margin-right: 6px; padding: 0 5px; border-radius: var(--r-hair); font-size: var(--fs-micro); }
4455
+ .ds-247420 .ds-live-log-preview { margin-left: 6px; color: var(--fg-3); word-break: break-word; }
4456
+
4457
+ /* Touch floors for the dense controls (not covered by the mobile width blocks). */
4458
+ @media (pointer: coarse) {
4459
+ .ds-247420 .ds-sub-btn { min-height: 44px; }
4460
+ .ds-247420 .ds-session-row { min-height: 44px; }
4461
+ .ds-247420 .ds-live-log-entry { padding-block: 6px; }
4462
+ }
4463
+
4464
+
4465
+ /* == appended: popovers-files == */
4466
+ /* FilePreviewMedia controls row — spacing + coarse-pointer tap floor */
4467
+ .ds-247420 .ds-preview-media-controls {
4468
+ display: flex;
4469
+ align-items: center;
4470
+ gap: var(--space-2);
4471
+ flex-wrap: wrap;
4472
+ }
4473
+ @media (hover: none), (pointer: coarse) {
4474
+ .ds-247420 .ds-preview-media-controls .chat-code-copy,
4475
+ .ds-247420 .chat-code-copy-head {
4476
+ min-height: 44px;
4477
+ min-width: 44px;
4478
+ }
4479
+ }
4480
+
4481
+ /* == appended: ui-kits == */
4482
+ /* ============================================================
4483
+ ui_kit responsive helpers (kits-grids sweep) */
4484
+ .ds-247420 .ds-section-pad { padding: clamp(6px, 1.2vw, 16px); }
4485
+ .ds-247420 .ds-panel-gap { margin: var(--space-2) 0; }
4486
+ .ds-247420 .ds-panel-duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin: var(--space-2) 0; }
4487
+ @media (max-width: 760px) {
4488
+ .ds-247420 .ds-panel-duo { grid-template-columns: 1fr; }
4489
+ }
4490
+ /* Wide-viewport density: auto-fit grid so panel COUNT tracks actual children
4491
+ instead of a hardcoded column number — 2 children sit 2-up, 5 wrap to a
4492
+ third row, never an arbitrary 3-card reflex (same auto-fit/minmax pattern
4493
+ as .ds-tile-grid). Panels floor at 280px before wrapping, so ultra-wide
4494
+ screens still get more columns than a fixed repeat(3, ...) ever allowed. */
4495
+ .ds-247420 .ds-panel-trio { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: var(--space-2); margin: var(--space-2) 0; }
4496
+ .ds-247420 .ds-panel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-2); margin: var(--space-2) 0; }
4497
+ /* wide dense rows/tables scroll inside their panel, never the page */
4498
+ .ds-247420 .ds-scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
4499
+
4500
+ /* --- slide deck ------------------------------------------- */
4501
+ .ds-247420 .ds-deck-stage {
4502
+ aspect-ratio: 16 / 9;
4503
+ width: 100%;
4504
+ max-width: min(1100px, 100%);
4505
+ margin: var(--space-3) auto;
4506
+ background: var(--bg-2);
4507
+ border-radius: var(--r-2);
4508
+ padding: clamp(16px, 5vw, 64px);
4509
+ box-sizing: border-box;
4510
+ display: flex;
4511
+ overflow: hidden;
4512
+ container-type: inline-size; /* cqw units track the stage, not the viewport */
4513
+ }
4514
+ @media (max-height: 500px) and (orientation: landscape) {
4515
+ .ds-247420 .ds-deck-stage {
4516
+ max-height: calc(100vh - 140px);
4517
+ max-height: calc(100dvh - 140px);
4518
+ aspect-ratio: auto;
4519
+ }
4520
+ }
4521
+ .ds-247420 .ds-deck-slide { flex: 1; display: flex; min-width: 0; }
4522
+ .ds-247420 .ds-deck-controls {
4523
+ display: flex; align-items: center; justify-content: center; gap: 14px;
4524
+ padding: 8px; font-family: var(--ff-mono); font-size: var(--fs-sm);
4525
+ }
4526
+ .ds-247420 .ds-deck-count { color: var(--fg-3); }
4527
+ @media (pointer: coarse) {
4528
+ .ds-247420 .ds-deck-controls .btn { min-height: 44px; min-width: 44px; }
4529
+ }
4530
+ .ds-247420 .ds-slide-eyebrow {
4531
+ font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.1em;
4532
+ text-transform: uppercase; color: var(--fg-3); margin-bottom: clamp(12px, 2.5cqw, 24px);
4533
+ }
4534
+ .ds-247420 .ds-slide-col { display: flex; flex-direction: column; justify-content: center; gap: clamp(12px, 2.5cqw, 24px); min-width: 0; }
4535
+ .ds-247420 .ds-slide-col--start { align-items: flex-start; }
4536
+ .ds-247420 .ds-slide-col--narrow { max-width: 38ch; }
4537
+ .ds-247420 .ds-slide-col--quote { max-width: 42ch; }
4538
+ .ds-247420 .ds-slide-hero {
4539
+ font-size: clamp(var(--fs-h2), 6cqw, var(--fs-hero));
4540
+ line-height: var(--lh-tight); letter-spacing: var(--tr-tight); font-weight: 600;
4541
+ color: var(--slide-accent, var(--accent-ink));
4542
+ overflow-wrap: anywhere;
4543
+ }
4544
+ .ds-247420 .ds-slide-h1 {
4545
+ font-size: clamp(var(--fs-h3), 4.5cqw, var(--fs-h1));
4546
+ line-height: var(--lh-snug); color: var(--fg); font-weight: 500; min-width: 0;
4547
+ }
4548
+ .ds-247420 .ds-slide-h1--lead { margin-bottom: 12px; }
4549
+ .ds-247420 .ds-slide-quote-body {
4550
+ font-size: clamp(var(--fs-lg), 3.5cqw, var(--fs-h2));
4551
+ line-height: var(--lh-snug); color: var(--fg); font-weight: 400; font-style: italic;
4552
+ }
4553
+ .ds-247420 .ds-slide-cite { font-family: var(--ff-mono); font-size: var(--fs-sm); color: var(--fg-3); }
4554
+ .ds-247420 .ds-slide-bullet {
4555
+ display: flex; gap: clamp(8px, 2vw, 18px); align-items: baseline;
4556
+ border-bottom: 1px solid var(--rule); padding: 12px 0; flex-wrap: wrap;
4557
+ }
4558
+ .ds-247420 .ds-slide-bullet-key {
4559
+ flex: 0 1 clamp(56px, 18%, 100px); min-width: 0;
4560
+ font-family: var(--ff-mono); font-size: var(--fs-sm);
4561
+ color: var(--slide-accent, var(--accent-ink));
4562
+ }
4563
+ .ds-247420 .ds-slide-bullet-val { color: var(--fg-2); font-size: var(--fs-lg); min-width: 0; }
4564
+ .ds-247420 .ds-slide-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(12px, 3vw, 32px); margin-top: 12px; }
4565
+ @media (max-width: 760px) {
4566
+ .ds-247420 .ds-slide-split { grid-template-columns: 1fr; }
4567
+ }
4568
+ .ds-247420 .ds-slide-split-cell {
4569
+ padding: 18px; background: var(--bg-2); border-radius: var(--r-2);
4570
+ color: var(--fg-2); font-size: var(--fs-lg); line-height: var(--lh-base); min-width: 0;
4571
+ }
4572
+ .ds-247420 .ds-slide-split-cell--accent { border-left: 3px solid var(--slide-accent, var(--accent)); }
4573
+
4574
+ /* --- error 404 --------------------------------------------- */
4575
+ .ds-247420 .ds-err-hero {
4576
+ padding: clamp(16px, 5vw, 36px) clamp(12px, 4vw, 22px);
4577
+ text-align: center; display: flex; flex-direction: column; gap: 14px; align-items: center;
4578
+ }
4579
+ .ds-247420 .ds-err-numeral {
4580
+ font-family: var(--ff-mono); font-size: clamp(56px, 20vw, 120px);
4581
+ line-height: 1; color: var(--panel-text-3); letter-spacing: -0.03em;
4582
+ }
4583
+ .ds-247420 .ds-err-path {
4584
+ display: inline-flex; gap: 6px; align-items: baseline; flex-wrap: wrap; max-width: 100%;
4585
+ font-family: var(--ff-mono); font-size: 13px; color: var(--panel-text-2);
4586
+ background: var(--panel-1); padding: 6px 12px; border-radius: var(--r-0);
4587
+ overflow-wrap: anywhere; word-break: break-all;
4588
+ }
4589
+
4590
+ /* --- gallery ------------------------------------------------ */
4591
+ .ds-247420 .ds-tile-grid {
4592
+ padding: clamp(8px, 2.5vw, 16px);
4593
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: 8px;
4594
+ }
4595
+ .ds-247420 .ds-tile-grid--tight { grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); }
4596
+ .ds-247420 .ds-swatch-grid {
4597
+ padding: clamp(8px, 2.5vw, 16px);
4598
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr)); gap: 12px;
4599
+ }
4600
+ .ds-247420 .ds-gallery-tile {
4601
+ cursor: pointer; display: flex; flex-direction: column; gap: 6px;
4602
+ padding: 12px; border-radius: var(--r-1); min-height: clamp(120px, 18vw, 160px);
4603
+ border: 0; text-align: left; font: inherit; color: inherit;
4604
+ background: var(--tile-tone, var(--panel-1));
4605
+ transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
4606
+ }
4607
+ /* Flat tonal fill only (house style: no bespoke tile chrome, no borders — see
4608
+ .ds-feature above), so the hover affordance is a lift, matching the same
4609
+ translateY + shadow idiom .chat-msg:hover .chat-bubble already uses. */
4610
+ .ds-247420 .ds-gallery-tile:hover { transform: translateY(-2px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 10%, transparent); }
4611
+ .ds-247420 .ds-gallery-tile:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
4612
+ .ds-247420 .ds-gallery-tile--tight { min-height: clamp(96px, 14vw, 120px); }
4613
+ .ds-247420 .ds-lightbox {
4614
+ position: fixed; inset: 0; background: var(--scrim);
4615
+ display: flex; align-items: center; justify-content: center;
4616
+ padding: clamp(12px, 4vw, 32px);
4617
+ padding-bottom: max(clamp(12px, 4vw, 32px), env(safe-area-inset-bottom));
4618
+ z-index: 50;
4619
+ }
4620
+ .ds-247420 .ds-lightbox-card {
4621
+ background: var(--panel-0); border-radius: var(--r-2); padding: clamp(16px, 4vw, 28px);
4622
+ width: min(520px, 100%); min-width: 0;
4623
+ max-height: calc(100vh - 24px);
4624
+ max-height: calc(100dvh - 24px);
4625
+ overflow: auto;
4626
+ display: flex; flex-direction: column; gap: 14px;
4627
+ }
4628
+ .ds-247420 .ds-lightbox-preview {
4629
+ padding: clamp(16px, 6vw, 36px); border-radius: var(--r-1); text-align: center;
4630
+ font-family: var(--ff-mono); white-space: pre-line; font-size: clamp(16px, 5vw, 24px);
4631
+ background: var(--tile-tone, var(--panel-1));
4632
+ }
4633
+
4634
+ /* --- search ------------------------------------------------- */
4635
+ .ds-247420 .ds-topbar-search { width: min(280px, 100%); min-width: 0; flex: 1 1 clamp(140px, 30vw, 280px); }
4636
+ @media (max-width: 480px) {
4637
+ .ds-247420 .ds-topbar-search { flex-basis: 100%; }
4638
+ }
4639
+ .ds-247420 .ds-empty-state { padding: clamp(16px, 5vw, 24px); text-align: center; color: var(--panel-text-3); }
4640
+ .ds-247420 .ds-empty-state-glyph { font-size: clamp(24px, 6vw, 32px); }
4641
+ .ds-247420 .ds-empty-state-msg { margin: 6px 0; }
4642
+ .ds-247420 .ds-empty-state-hint { margin: 0; font-size: var(--fs-sm); }
4643
+
4644
+ /* --- system primer ------------------------------------------ */
4645
+ .ds-247420 .ds-swatch-grid-sm {
4646
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(110px, 100%), 1fr));
4647
+ gap: 12px; padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px);
4648
+ }
4649
+ .ds-247420 .ds-swatch-grid-lg { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); }
4650
+ .ds-247420 .ds-swatch-col { display: flex; flex-direction: column; gap: 6px; }
4651
+ .ds-247420 .ds-swatch-chip { height: 48px; border-radius: var(--r-1); border: 1px solid var(--rule); background: var(--swatch, var(--panel-1)); }
4652
+ .ds-247420 .ds-swatch-chip--big { height: 64px; }
4653
+ .ds-247420 .ds-swatch-name { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
4654
+ .ds-247420 .ds-type-panel { padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px); display: flex; flex-direction: column; gap: 14px; }
4655
+ .ds-247420 .ds-type-row {
4656
+ display: flex; align-items: baseline; gap: 14px;
4657
+ border-bottom: 1px solid var(--rule); padding-bottom: 8px; flex-wrap: wrap;
4658
+ }
4659
+ .ds-247420 .ds-type-row-label { flex: 0 0 64px; font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
4660
+ .ds-247420 .ds-type-sample {
4661
+ min-width: 0; overflow-wrap: anywhere; line-height: var(--lh-tight); color: var(--fg);
4662
+ font-size: var(--sample-size, var(--fs-body));
4663
+ }
4664
+ .ds-247420 .ds-prim-panel { padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px); display: flex; flex-direction: column; gap: 18px; }
4665
+ .ds-247420 .ds-prim-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
4666
+ .ds-247420 .ds-prim-label { flex: 0 0 64px; font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
4667
+
4668
+ /* == appended: content-site == */
4669
+ /* Home landing wrappers (site/theme.mjs) — replace banned inline styles. */
4670
+ .ds-247420 .ds-home-hero-wrap { padding: 0 var(--space-2, 8px); }
4671
+ .ds-247420 .ds-home-panel { margin: var(--space-2, 8px); }
4672
+ @media (max-width: 480px) {
4673
+ .ds-247420 .ds-home-panel { margin: var(--space-1, 4px) 0; }
4674
+ }
4675
+ .ds-247420 .ds-quickstart {
4676
+ padding: var(--space-3, 16px) var(--space-4, 22px);
4677
+ display: flex;
4678
+ flex-direction: column;
4679
+ gap: 6px;
4680
+ }
4681
+ /* Table() scroll containment — wide tables scroll inside their own box,
4682
+ never the page body. */
4683
+ .ds-247420 .ds-table-wrap {
4684
+ overflow-x: auto;
4685
+ -webkit-overflow-scrolling: touch;
4686
+ max-width: 100%;
4687
+ }
4688
+ .ds-247420 .ds-table-wrap > table { min-width: 100%; }
4689
+
4690
+
4691
+ /* == appended: settings kit cleanup == */
4692
+ /* == appended: settings kit == */
4693
+ .ds-247420 .ds-settings-main { padding: 8px; }
4694
+ .ds-247420 .ds-settings-body { padding: 14px 18px; }
4695
+ .ds-247420 .ds-settings-body-stack { display: flex; flex-direction: column; gap: 10px; }
4696
+ .ds-247420 .ds-field-block { margin: 10px 0; }
4697
+ .ds-247420 .ds-field-eyebrow {
4698
+ font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.06em;
4699
+ text-transform: uppercase; color: var(--panel-text-3);
4700
+ }
4701
+ .ds-247420 .ds-hint-sm { font-size: 12px; color: var(--panel-text-2); }
4702
+ .ds-247420 .ds-note-quiet { margin: 0; color: var(--panel-text-2); }
4703
+ .ds-247420 .ds-btn-row { display: flex; gap: 8px; flex-wrap: wrap; }
4704
+ .ds-247420 .ds-btn-row-tight { gap: 6px; }
4705
+ .ds-247420 .ds-key-input { flex: 1 1 160px; min-width: 0; font-family: var(--ff-mono); }
4706
+ .ds-247420 .ds-toggle-btn { min-width: 78px; }
4707
+ .ds-247420 .ds-toggle-label { margin-left: 8px; color: inherit; opacity: 0.7; }
4708
+ .ds-247420 .ds-btn-warn { color: var(--warn); }
4709
+ .ds-247420 .ds-btn-mascot { color: var(--mascot); }
4710
+ .ds-247420 .ds-savebar {
4711
+ position: sticky; bottom: 8px; display: flex; align-items: center;
4712
+ justify-content: flex-end; gap: 8px; flex-wrap: wrap; padding: 10px;
4713
+ background: var(--panel-2); border-radius: var(--r-1); margin: 8px 0;
4714
+ }
4715
+ .ds-247420 .ds-savebar-note { flex: 1 1 160px; min-width: 0; color: var(--panel-text-2); }
4716
+ .ds-247420 .ds-settings-modal { min-width: min(320px, calc(100vw - 32px)); max-width: 480px; }
4717
+ .ds-247420 .ds-modal-body-form { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
4718
+ .ds-247420 .ds-modal-note { margin: 0 0 8px; color: var(--panel-text-2); font-size: 14px; }
4719
+ .ds-247420 .ds-draft-preview {
4720
+ background: var(--panel-1); padding: 12px; border-radius: var(--r-0);
4721
+ font-size: 13px; color: var(--panel-text-2); max-height: 120px;
4722
+ overflow-y: auto; font-family: var(--ff-mono); overflow-wrap: anywhere;
4723
+ }
4724
+ .ds-247420 .ds-modal-actions { display: flex; gap: 8px; margin-top: 12px; justify-content: space-between; flex-wrap: wrap; }
4725
+
4726
+ /* == appended: signin kit cleanup == */
4727
+ /* -- signin kit (ui_kits/signin) -- */
4728
+ .ds-247420 .ds-auth-wrap { padding: var(--space-2, 8px); display: flex; flex-direction: column; align-items: center; }
4729
+ .ds-247420 .ds-auth-col { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: 8px; margin: clamp(12px, 4vw, 24px) 0; min-width: 0; }
4730
+ .ds-247420 .ds-auth-form { padding: clamp(12px, 3vw, 18px); display: flex; flex-direction: column; gap: 10px; }
4731
+ .ds-247420 .ds-auth-sent { align-items: center; text-align: center; }
4732
+ .ds-247420 .ds-auth-sent-glyph { font-size: 32px; color: var(--panel-accent); }
4733
+ .ds-247420 .ds-auth-sent-title { margin: 0; font-weight: 600; }
4734
+ .ds-247420 .ds-auth-sent-sub { margin: 0; color: var(--panel-text-2); overflow-wrap: anywhere; }
4735
+ .ds-247420 .ds-auth-field { display: flex; flex-direction: column; gap: 4px; }
4736
+ .ds-247420 .ds-auth-field-label { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--panel-text-3); }
4737
+ .ds-247420 .ds-auth-row-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
4738
+ .ds-247420 .ds-auth-remember { display: flex; align-items: center; gap: 6px; cursor: pointer; }
4739
+ .ds-247420 .ds-auth-remember-text { color: var(--panel-text-2); font-size: 13px; }
4740
+ .ds-247420 .ds-auth-forgot { font-size: 13px; }
4741
+ .ds-247420 .ds-auth-error { padding: 8px 10px; background: var(--panel-1); border-radius: var(--r-0); color: var(--danger); font-size: 13px; overflow-wrap: anywhere; }
4742
+ .ds-247420 .ds-auth-divider { display: flex; align-items: center; gap: 10px; margin: 6px 0; color: var(--panel-text-3); font-size: 12px; }
4743
+ .ds-247420 .ds-auth-divider-line { flex: 1; height: 1px; background: var(--panel-2); }
4744
+ .ds-247420 .ds-auth-providers { display: flex; gap: 8px; flex-wrap: wrap; }
4745
+ .ds-247420 .ds-auth-provider-btn { flex: 1 1 100px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px; }
4746
+ .ds-247420 .ds-auth-provider-btn--loading { opacity: 0.7; pointer-events: none; }
4747
+ .ds-247420 .ds-auth-provider-glyph { font-family: var(--ff-mono); color: var(--panel-text-3); display: inline-flex; }
4748
+ .ds-247420 .ds-auth-modes { display: flex; justify-content: center; gap: 14px; margin-top: 8px; font-size: 13px; flex-wrap: wrap; }
4749
+ .ds-247420 .ds-auth-mode-link { color: var(--panel-text-3); text-decoration: none; }
4750
+ .ds-247420 .ds-auth-mode-link--active { color: var(--panel-text); text-decoration: underline; }
4751
+ .ds-247420 .ds-auth-fineprint { text-align: center; font-size: 12px; color: var(--panel-text-3); margin: 6px 0; }
4752
+
4753
+ /* == appended: gallery-misc kit cleanup == */
4754
+ /* --- shared helpers (converted from inline styles) --- */
4755
+ .ds-247420 .ds-m0 { margin: 0; }
4756
+ .ds-247420 .ds-text-2 { color: var(--panel-text-2); }
4757
+ .ds-247420 .ds-text-3 { color: var(--panel-text-3); }
4758
+ .ds-247420 .ds-kit-head { display: flex; align-items: center; justify-content: space-between; gap: clamp(8px, 2vw, 16px); flex-wrap: wrap; }
4759
+
4760
+ /* --- gallery kit --- */
4761
+ .ds-247420 .ds-tile-cap { flex: 1; display: flex; align-items: center; justify-content: center; font-family: var(--ff-mono); white-space: pre-line; color: var(--panel-text-2); font-size: 18px; min-width: 0; text-align: center; }
4762
+ .ds-247420 .ds-tile-meta { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; flex-wrap: wrap; min-width: 0; }
4763
+ .ds-247420 .ds-tile-glyph { font-family: var(--ff-mono); color: var(--panel-text-3); }
4764
+ .ds-247420 .ds-tile-label { color: var(--panel-text); overflow-wrap: anywhere; }
4765
+ .ds-247420 .ds-gal-swatch { height: 64px; border-radius: var(--r-0); background: var(--swatch, var(--panel-1)); }
4766
+ .ds-247420 .ds-gal-swatch-meta { display: flex; justify-content: space-between; gap: 6px; flex-wrap: wrap; font-family: var(--ff-mono); font-size: 11px; min-width: 0; }
4767
+ .ds-247420 .ds-gal-swatch-name { color: var(--panel-text); }
4768
+ .ds-247420 .ds-gal-swatch-hint { color: var(--panel-text-3); overflow-wrap: anywhere; }
4769
+ .ds-247420 .ds-lightbox-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
4770
+ .ds-247420 .ds-lightbox-tag { font-family: var(--ff-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--panel-text-3); }
4771
+
4772
+ /* --- error_404 kit --- */
4773
+ .ds-247420 .ds-err-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
4774
+ .ds-247420 .ds-err-chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; margin-top: 4px; }
4775
+
4776
+ /* == appended: terminal-capp kit cleanup == */
4777
+ /* --- terminal kit ------------------------------------------ */
4778
+ .ds-247420 .ds-section-pad-sm { padding: 8px; }
4779
+ .ds-247420 .ds-kit-head-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
4780
+ .ds-247420 .ds-cli-cmt .cmd { color: var(--fg-3); }
4781
+ .ds-247420 .ds-cli-out .cmd { color: var(--fg-2); }
4782
+ .ds-247420 .ds-cli-ok .prompt, .ds-247420 .ds-cli-ok .cmd { color: var(--accent-ink); }
4783
+ .ds-247420 .ds-cli-warn .prompt, .ds-247420 .ds-cli-warn .cmd { color: var(--mascot); }
4784
+ .ds-247420 .ds-cli-log .prompt { color: var(--fg-3); }
4785
+ .ds-247420 .ds-cli-log .cmd { color: var(--fg-2); font-family: var(--ff-mono); }
4786
+ .ds-247420 .ds-term-body { padding: 14px 18px; display: flex; flex-direction: column; gap: 4px; background: var(--bg-2); border-radius: var(--r-1); }
4787
+ .ds-247420 .ds-term-body--tall { min-height: 280px; }
4788
+ .ds-247420 .ds-term-input-row { margin-top: 6px; }
4789
+ .ds-247420 .ds-term-input { flex: 1; min-width: 0; background: transparent; border: 0; outline: 0; font-family: var(--ff-mono); font-size: 13px; color: var(--fg); }
4790
+ /* full-viewport render root (community-app) */
4791
+ .ds-247420 .ds-root-viewport { height: 100vh; height: 100dvh; }
4792
+
4793
+ /* --- chat kit: widescreen detail pane -----------------------
4794
+ .chat itself stays single-column (shared component, untouched) and
4795
+ stretches full-width on ultrawide via the existing .app-main > .chat
4796
+ max-width:none rule above (~L380) — that's fine for a bare thread, but
4797
+ it leaves a lone thread column growing to 1400px+ with no other use of
4798
+ the extra width. This wrapper adds a persistent "thread info" rail once
4799
+ there is room to spare, instead of just widening the message column. */
4800
+ .ds-247420 .ds-chat-layout { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: var(--space-3); }
4801
+ .ds-247420 .ds-chat-layout > .chat { min-width: 0; }
4802
+ .ds-247420 .ds-chat-detail { display: none; }
4803
+ @media (min-width: 1100px) {
4804
+ .ds-247420 .ds-chat-layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; align-items: start; gap: var(--space-4); }
4805
+ .ds-247420 .ds-chat-detail { display: block; position: sticky; top: 0; }
4080
4806
  }
4081
4807
 
4082
4808
  /* community.css */
@@ -4092,8 +4818,13 @@
4092
4818
  .ds-247420 .cm-shell {
4093
4819
  display: flex;
4094
4820
  height: 100vh;
4821
+ height: 100dvh;
4095
4822
  width: 100%;
4096
4823
  overflow: hidden;
4824
+ /* Notched devices: keep the rail and bottom chrome out of the unsafe zones. */
4825
+ padding-bottom: env(safe-area-inset-bottom);
4826
+ padding-left: env(safe-area-inset-left);
4827
+ padding-right: env(safe-area-inset-right);
4097
4828
  background: var(--bg);
4098
4829
  color: var(--fg);
4099
4830
  font-family: var(--ff-body);
@@ -4177,7 +4908,7 @@
4177
4908
  width: 4px;
4178
4909
  height: 8px;
4179
4910
  background: var(--fg);
4180
- border-radius: 0 4px 4px 0;
4911
+ border-radius: 0 var(--r-0) var(--r-0) 0;
4181
4912
  transition: height var(--dur-base) var(--ease);
4182
4913
  }
4183
4914
  .ds-247420 .cm-server-icon:hover .cm-server-pill { height: 20px; }
@@ -4233,7 +4964,7 @@
4233
4964
  width: 32px;
4234
4965
  height: 2px;
4235
4966
  background: color-mix(in oklab, var(--fg) 12%, transparent);
4236
- border-radius: 2px;
4967
+ border-radius: var(--r-hair);
4237
4968
  margin: 4px 0;
4238
4969
  flex-shrink: 0;
4239
4970
  }
@@ -4294,7 +5025,7 @@
4294
5025
  .ds-247420 .cm-channel-list::-webkit-scrollbar-track { background: transparent; }
4295
5026
  .ds-247420 .cm-channel-list::-webkit-scrollbar-thumb {
4296
5027
  background: color-mix(in oklab, var(--fg) 18%, transparent);
4297
- border-radius: 4px;
5028
+ border-radius: var(--r-0);
4298
5029
  }
4299
5030
 
4300
5031
  /* ============================================================
@@ -4374,7 +5105,7 @@
4374
5105
  background: color-mix(in oklab, var(--fg) 8%, transparent);
4375
5106
  }
4376
5107
  .ds-247420 .cm-cat-add:focus-visible {
4377
- outline: 2px solid var(--accent);
5108
+ outline: 2px solid var(--accent-ink);
4378
5109
  outline-offset: 2px;
4379
5110
  }
4380
5111
 
@@ -4426,7 +5157,7 @@
4426
5157
  bottom: 4px;
4427
5158
  width: 3px;
4428
5159
  background: var(--accent);
4429
- border-radius: 0 3px 3px 0;
5160
+ border-radius: 0 var(--r-hair) var(--r-hair) 0;
4430
5161
  }
4431
5162
 
4432
5163
  .ds-247420 .cm-channel-item.voice-active {
@@ -4555,7 +5286,7 @@
4555
5286
  background: color-mix(in oklab, var(--fg) 10%, transparent);
4556
5287
  }
4557
5288
  .ds-247420 .cm-ch-action-btn:focus-visible {
4558
- outline: 2px solid var(--accent);
5289
+ outline: 2px solid var(--accent-ink);
4559
5290
  outline-offset: 2px;
4560
5291
  }
4561
5292
 
@@ -4880,7 +5611,7 @@
4880
5611
  scrollbar-width: thin;
4881
5612
  scrollbar-color: color-mix(in oklab, var(--fg) 18%, transparent) transparent;
4882
5613
  transition: width var(--dur-base) var(--ease), flex-basis var(--dur-base) var(--ease);
4883
- will-change: width, flex-basis, opacity, transform; contain: layout style;
5614
+ contain: layout style;
4884
5615
  }
4885
5616
  .ds-247420 .cm-member-list:not(.open) {
4886
5617
  width: 0;
@@ -4894,7 +5625,7 @@
4894
5625
  .ds-247420 .cm-member-list::-webkit-scrollbar { width: 8px; }
4895
5626
  .ds-247420 .cm-member-list::-webkit-scrollbar-thumb {
4896
5627
  background: color-mix(in oklab, var(--fg) 18%, transparent);
4897
- border-radius: 4px;
5628
+ border-radius: var(--r-0);
4898
5629
  }
4899
5630
 
4900
5631
  .ds-247420 .cm-member-category {
@@ -5025,7 +5756,7 @@
5025
5756
  /* ============================================================
5026
5757
  Responsive — collapse sidebars on narrow viewports
5027
5758
  ============================================================ */
5028
- @media (max-width: 768px) {
5759
+ @media (max-width: 900px) {
5029
5760
  .ds-247420 .cm-channel-sidebar {
5030
5761
  position: absolute;
5031
5762
  z-index: 20;
@@ -5052,6 +5783,21 @@
5052
5783
  .ds-247420 .cm-chat-header-topic { display: none; }
5053
5784
  }
5054
5785
 
5786
+ /* Drawer scrim — dims the chat while a drawer overlays it on narrow screens.
5787
+ Visual affordance only (pointer-events: none): tap-to-close needs a real
5788
+ element + handler in CommunityShell, which lives outside this stylesheet. */
5789
+ @media (max-width: 900px) {
5790
+ .ds-247420 .cm-shell:has(.cm-channel-sidebar.open) .cm-main::before,
5791
+ .ds-247420 .cm-shell:has(.cm-member-list.open) .cm-main::before {
5792
+ content: '';
5793
+ position: absolute;
5794
+ inset: 0;
5795
+ z-index: 15;
5796
+ background: color-mix(in oklab, var(--ink) 40%, transparent);
5797
+ pointer-events: none;
5798
+ }
5799
+ }
5800
+
5055
5801
  @media (max-width: 480px) {
5056
5802
  .ds-247420 .cm-server-rail {
5057
5803
  flex: 0 0 56px;
@@ -5064,22 +5810,12 @@
5064
5810
  height: 44px;
5065
5811
  padding: 4px;
5066
5812
  }
5067
- .ds-247420 .cm-channel-sidebar {
5068
- left: 56px;
5069
- width: 80vw;
5070
- max-width: 200px;
5071
- }
5813
+ .ds-247420 .cm-channel-sidebar,
5072
5814
  .ds-247420 .cm-channel-sidebar.open {
5815
+ left: 56px;
5073
5816
  width: 80vw;
5074
- max-width: 200px;
5075
- }
5076
-
5077
- /* Mobile touch target fixes for icon buttons */
5078
- .ds-247420 .cm-cat-add,
5079
- .ds-247420 .cm-ch-action-btn {
5080
- width: 44px;
5081
- height: 44px;
5082
- padding: 8px;
5817
+ /* Use the width beside the 56px rail, not a 200px sliver. */
5818
+ max-width: min(320px, calc(100vw - 56px));
5083
5819
  }
5084
5820
  .ds-247420 .cm-ch-icon {
5085
5821
  flex: 0 0 24px;
@@ -5088,6 +5824,44 @@
5088
5824
  }
5089
5825
  }
5090
5826
 
5827
+ /* Touch target floors — applies on any coarse-pointer device (phones AND
5828
+ touch tablets/laptops), not just narrow viewports. */
5829
+ @media (pointer: coarse) {
5830
+ .ds-247420 .cm-channel-item,
5831
+ .ds-247420 .cm-member-item { min-height: 44px; }
5832
+ .ds-247420 .cm-cat-add,
5833
+ .ds-247420 .cm-ch-action-btn,
5834
+ .ds-247420 .cm-user-btn,
5835
+ .ds-247420 .cm-vs-btn,
5836
+ .ds-247420 .cm-tp-new,
5837
+ .ds-247420 .cm-tp-close,
5838
+ .ds-247420 .cm-rb-cancel,
5839
+ .ds-247420 .cm-mh-btn {
5840
+ min-width: 44px;
5841
+ min-height: 44px;
5842
+ }
5843
+ .ds-247420 .cm-forum-search,
5844
+ .ds-247420 .cm-forum-sort,
5845
+ .ds-247420 .cm-forum-new { min-height: 44px; }
5846
+ }
5847
+
5848
+ /* Ultrawide: clamp the message/forum/page column to a readable measure. */
5849
+ @media (min-width: 1600px) {
5850
+ .ds-247420 .cm-main > .chat,
5851
+ .ds-247420 .cm-forum-list,
5852
+ .ds-247420 .cm-page-body {
5853
+ max-width: 110ch;
5854
+ margin-inline: auto;
5855
+ width: 100%;
5856
+ }
5857
+ }
5858
+
5859
+ /* No hover on touch: hover-revealed channel actions must stay reachable. */
5860
+ @media (hover: none) {
5861
+ .ds-247420 .cm-channel-item .cm-ch-actions { opacity: 0.6; }
5862
+ .ds-247420 .cm-category-header .cm-cat-add { opacity: 0.6; }
5863
+ }
5864
+
5091
5865
  /* ---------- a11y polish: focus-visible coverage on community interactive elements ---------- */
5092
5866
  /* Every interactive surface with a :hover state must also have a :focus-visible state so
5093
5867
  keyboard users get equivalent feedback. The selectors here mirror the existing :hover rules. */
@@ -5095,53 +5869,53 @@
5095
5869
  .ds-247420 .cm-server-icon:focus-visible,
5096
5870
  .ds-247420 .cm-server-back:focus-visible,
5097
5871
  .ds-247420 .cm-server-add:focus-visible {
5098
- outline: 2px solid var(--accent);
5872
+ outline: 2px solid var(--accent-ink);
5099
5873
  outline-offset: 2px;
5100
5874
  border-radius: var(--r-2);
5101
5875
  }
5102
5876
 
5103
5877
  .ds-247420 .cm-channel-item:focus-visible {
5104
- outline: 2px solid var(--accent);
5878
+ outline: 2px solid var(--accent-ink);
5105
5879
  outline-offset: -2px;
5106
5880
  border-radius: var(--r-1);
5107
5881
  }
5108
5882
 
5109
5883
  .ds-247420 .cm-server-header:focus-visible,
5110
5884
  .ds-247420 .cm-category-header:focus-visible {
5111
- outline: 2px solid var(--accent);
5885
+ outline: 2px solid var(--accent-ink);
5112
5886
  outline-offset: -2px;
5113
5887
  }
5114
5888
 
5115
5889
  .ds-247420 .cm-member-item:focus-visible {
5116
- outline: 2px solid var(--accent);
5890
+ outline: 2px solid var(--accent-ink);
5117
5891
  outline-offset: -2px;
5118
5892
  border-radius: var(--r-1);
5119
5893
  }
5120
5894
 
5121
5895
  .ds-247420 .cm-vs-btn:focus-visible,
5122
5896
  .ds-247420 .cm-user-btn:focus-visible {
5123
- outline: 2px solid var(--accent);
5897
+ outline: 2px solid var(--accent-ink);
5124
5898
  outline-offset: 2px;
5125
5899
  border-radius: var(--r-1);
5126
5900
  }
5127
5901
 
5128
5902
  /* ThreadPanel / Forum / Page interactive elements */
5129
5903
  .ds-247420 .cm-tp-item:focus-visible,
5130
- .ds-247420 .cm-forum-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-1); }
5904
+ .ds-247420 .cm-forum-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; border-radius: var(--r-1); }
5131
5905
  .ds-247420 .cm-tp-new:focus-visible,
5132
5906
  .ds-247420 .cm-tp-close:focus-visible,
5133
5907
  .ds-247420 .cm-forum-new:focus-visible,
5134
5908
  .ds-247420 .cm-forum-sort:focus-visible,
5135
- .ds-247420 .cm-page-edit:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-1); }
5136
- .ds-247420 .cm-forum-search:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
5909
+ .ds-247420 .cm-page-edit:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-1); }
5910
+ .ds-247420 .cm-forum-search:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent-ink); }
5137
5911
 
5138
5912
  /* ---------- mobile header ---------- */
5139
5913
  .ds-247420 .cm-mobile-header {
5140
5914
  display: flex;
5141
5915
  align-items: center;
5142
5916
  gap: var(--space-2);
5143
- height: 48px;
5144
- padding: 0 var(--space-2);
5917
+ height: calc(48px + env(safe-area-inset-top));
5918
+ padding: env(safe-area-inset-top) max(var(--space-2), env(safe-area-inset-right)) 0 max(var(--space-2), env(safe-area-inset-left));
5145
5919
  background: var(--bg-2);
5146
5920
  border-bottom: 1px solid var(--panel-3);
5147
5921
  }
@@ -5161,7 +5935,7 @@
5161
5935
  border-radius: var(--r-1);
5162
5936
  }
5163
5937
  .ds-247420 .cm-mh-btn:hover { background: var(--panel-3); }
5164
- .ds-247420 .cm-mh-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
5938
+ .ds-247420 .cm-mh-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
5165
5939
  .ds-247420 .cm-mh-title {
5166
5940
  flex: 1 1 auto;
5167
5941
  min-width: 0;
@@ -5206,7 +5980,7 @@
5206
5980
  border-radius: var(--r-1);
5207
5981
  }
5208
5982
  .ds-247420 .cm-rb-cancel:hover { background: var(--panel-3); color: var(--fg); }
5209
- .ds-247420 .cm-rb-cancel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
5983
+ .ds-247420 .cm-rb-cancel:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
5210
5984
 
5211
5985
  /* ---------- banner ---------- */
5212
5986
  .ds-247420 .cm-banner {
@@ -5219,6 +5993,7 @@
5219
5993
  font-weight: 500;
5220
5994
  }
5221
5995
  .ds-247420 .cm-banner.clickable { cursor: pointer; }
5996
+ .ds-247420 .cm-banner.clickable:hover { background: color-mix(in oklab, currentColor 10%, transparent); }
5222
5997
  .ds-247420 .cm-banner-msg { flex: 1 1 auto; min-width: 0; }
5223
5998
  .ds-247420 .cm-banner-action {
5224
5999
  flex: none;
@@ -5295,6 +6070,7 @@
5295
6070
  touch-action: none;
5296
6071
  transition: background var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), transform var(--dur-snap) var(--ease);
5297
6072
  }
6073
+ .ds-247420 .vx-ptt:hover { background: color-mix(in oklab, var(--fg) 8%, var(--bg-2)); }
5298
6074
  .ds-247420 .vx-ptt:active { transform: scale(0.97); }
5299
6075
  .ds-247420 .vx-ptt-icon { font-size: var(--fs-xl); line-height: 1; }
5300
6076
  .ds-247420 .vx-ptt-label { font-size: var(--fs-tiny); letter-spacing: var(--tr-label); text-transform: uppercase; }
@@ -5404,6 +6180,7 @@
5404
6180
  cursor: pointer;
5405
6181
  transition: background var(--dur-base) var(--ease);
5406
6182
  }
6183
+ .ds-247420 .vx-btn:hover { background: var(--bg-4, var(--bg-3)); }
5407
6184
  .ds-247420 .vx-btn-on, .ds-247420 .vx-btn-primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
5408
6185
 
5409
6186
  .ds-247420 .vx-modal-backdrop {
@@ -5416,6 +6193,7 @@
5416
6193
  .ds-247420 .vx-modal {
5417
6194
  width: 100%; max-width: 440px;
5418
6195
  max-height: 90vh;
6196
+ max-height: 90dvh;
5419
6197
  display: flex; flex-direction: column;
5420
6198
  border-radius: var(--r-3);
5421
6199
  background: var(--bg);
@@ -5433,6 +6211,7 @@
5433
6211
  border: 0; background: transparent; color: var(--fg-3);
5434
6212
  font-size: var(--fs-xl); line-height: 1; cursor: pointer; padding: 0 var(--space-1);
5435
6213
  }
6214
+ .ds-247420 .vx-modal-x:hover { color: var(--fg); }
5436
6215
  .ds-247420 .vx-modal-body { padding: var(--space-3); overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-3); }
5437
6216
  .ds-247420 .vx-modal-foot {
5438
6217
  display: flex; justify-content: flex-end; gap: var(--space-2);
@@ -5490,6 +6269,7 @@
5490
6269
  cursor: pointer;
5491
6270
  font-size: var(--fs-sm);
5492
6271
  }
6272
+ .ds-247420 .vx-queue-btn:hover { background: var(--bg-4, var(--bg-2)); }
5493
6273
  .ds-247420 .vx-queue-strip {
5494
6274
  display: flex; gap: var(--space-2);
5495
6275
  overflow-x: auto;
@@ -5507,6 +6287,7 @@
5507
6287
  font-size: var(--fs-tiny);
5508
6288
  cursor: pointer;
5509
6289
  }
6290
+ .ds-247420 .vx-chip:hover { background: var(--bg-4, var(--bg-2)); border-color: var(--rule-strong); }
5510
6291
  .ds-247420 .vx-chip-current { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 16%, var(--bg-3)); }
5511
6292
  .ds-247420 .vx-chip-live { border-color: var(--green-2); }
5512
6293
  .ds-247420 .vx-chip-dot { width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--fg-3); flex-shrink: 0; }
@@ -5541,10 +6322,21 @@
5541
6322
  /* ThreadPanel — cm-thread-panel / cm-tp-* */
5542
6323
  .ds-247420 .cm-thread-panel {
5543
6324
  display: flex; flex-direction: column;
6325
+ flex: 0 0 300px; width: 300px; min-width: 0;
5544
6326
  height: 100%; min-height: 0;
5545
6327
  background: var(--bg-2); color: var(--fg);
5546
6328
  border-left: var(--bw-hair) solid var(--rule);
5547
6329
  }
6330
+ @media (max-width: 900px) {
6331
+ .ds-247420 .cm-thread-panel {
6332
+ position: absolute;
6333
+ z-index: 20;
6334
+ top: 0; right: 0; bottom: 0;
6335
+ height: auto;
6336
+ width: min(320px, 90vw);
6337
+ box-shadow: -2px 0 16px color-mix(in oklab, var(--ink) 30%, transparent);
6338
+ }
6339
+ }
5548
6340
  .ds-247420 .cm-tp-head {
5549
6341
  display: flex; align-items: center; justify-content: space-between;
5550
6342
  padding: var(--space-2); border-bottom: var(--bw-hair) solid var(--rule);
@@ -5558,6 +6350,7 @@
5558
6350
  .ds-247420 .cm-tp-new:hover, .ds-247420 .cm-tp-close:hover { background: var(--bg-3); color: var(--fg); }
5559
6351
  .ds-247420 .cm-tp-list { flex: 1; min-height: 0; overflow-y: auto; }
5560
6352
  .ds-247420 .cm-tp-item {
6353
+ position: relative; /* anchors .cm-tp-dot to the row, not the panel */
5561
6354
  display: flex; flex-direction: column; gap: 2px;
5562
6355
  width: 100%; text-align: left; cursor: pointer;
5563
6356
  padding: var(--space-2); border: none; background: transparent;
@@ -5567,15 +6360,52 @@
5567
6360
  .ds-247420 .cm-tp-item:hover { background: var(--bg-3); }
5568
6361
  .ds-247420 .cm-tp-item.is-active { background: var(--bg-3); box-shadow: inset 3px 0 0 var(--accent); }
5569
6362
  .ds-247420 .cm-tp-item.is-unread .cm-tp-item-title { font-weight: 700; }
5570
- .ds-247420 .cm-tp-dot { position: absolute; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
6363
+ .ds-247420 .cm-tp-dot { position: absolute; left: 4px; top: 50%; transform: translateY(-50%); width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
5571
6364
  .ds-247420 .cm-tp-item-title { font-size: var(--fs-1, 14px); }
5572
6365
  .ds-247420 .cm-tp-item-snippet { font-size: var(--fs-0, 12px); color: var(--fg-2, var(--fg)); opacity: .8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5573
6366
  .ds-247420 .cm-tp-item-meta { display: flex; gap: var(--space-2); font-size: var(--fs-micro, 11px); color: var(--fg-2, var(--fg)); opacity: .7; }
5574
- .ds-247420 .cm-tp-empty, .ds-247420 .cm-forum-empty, .ds-247420 .cm-channel-empty, .ds-247420 .cm-member-empty { padding: var(--space-3); text-align: center; color: var(--fg-2, var(--fg)); opacity: .7; font-size: var(--fs-sm); }
6367
+ .ds-247420 .cm-tp-empty, .ds-247420 .cm-forum-empty, .ds-247420 .cm-channel-empty, .ds-247420 .cm-member-empty {
6368
+ display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
6369
+ padding: var(--space-4) var(--space-3); text-align: center;
6370
+ color: var(--fg-2, var(--fg)); opacity: .7; font-size: var(--fs-sm);
6371
+ }
6372
+ .ds-247420 .cm-tp-empty svg, .ds-247420 .cm-forum-empty svg, .ds-247420 .cm-channel-empty svg, .ds-247420 .cm-member-empty svg { opacity: .6; }
6373
+
6374
+ /* Loading skeletons — cold-load placeholders for channel/member/thread/forum
6375
+ lists. Same .ds-skel shimmer primitive as sessions.js/files.js so every
6376
+ list surface in the kit uses one shimmer language, never a bare spinner. */
6377
+ .ds-247420 .cm-channel-item-skeleton, .ds-247420 .cm-member-item-skeleton {
6378
+ display: flex; align-items: center; gap: var(--space-2);
6379
+ padding: var(--space-2); margin: 2px var(--space-1);
6380
+ }
6381
+ .ds-247420 .cm-channel-item-skeleton .ds-skel-icon, .ds-247420 .cm-member-item-skeleton .ds-skel-icon {
6382
+ width: 20px; height: 20px; border-radius: var(--r-round, 50%); flex: none; background: var(--bg-3);
6383
+ }
6384
+ .ds-247420 .cm-channel-item-skeleton .ds-skel-title, .ds-247420 .cm-member-item-skeleton .ds-skel-title {
6385
+ height: 12px; width: 60%; border-radius: var(--r-1); background: var(--bg-3);
6386
+ }
6387
+ .ds-247420 .cm-list-item-skeleton {
6388
+ display: flex; flex-direction: column; gap: 6px;
6389
+ padding: var(--space-2) var(--space-3); border-bottom: var(--bw-hair) solid var(--rule);
6390
+ }
6391
+ .ds-247420 .cm-list-item-skeleton .ds-skel-title { height: 12px; width: 55%; border-radius: var(--r-1); background: var(--bg-3); }
6392
+ .ds-247420 .cm-list-item-skeleton .ds-skel-meta { height: 9px; width: 35%; border-radius: var(--r-1); background: var(--bg-3); }
6393
+ /* Self-contained shimmer keyframe: community.css ships standalone (the
6394
+ community-app kit does not also load chat.css), so this cannot depend on
6395
+ chat.css's ds-skel-shimmer definition even though the visual language and
6396
+ token vocabulary match it exactly. */
6397
+ @media (prefers-reduced-motion: no-preference) {
6398
+ .ds-247420 .cm-channel-item-skeleton .ds-skel-icon, .ds-247420 .cm-channel-item-skeleton .ds-skel-title, .ds-247420 .cm-member-item-skeleton .ds-skel-icon, .ds-247420 .cm-member-item-skeleton .ds-skel-title, .ds-247420 .cm-list-item-skeleton .ds-skel-title, .ds-247420 .cm-list-item-skeleton .ds-skel-meta {
6399
+ animation: cm-skel-shimmer 1.3s ease-in-out infinite;
6400
+ background: linear-gradient(90deg, var(--bg-3) 0%, var(--bg-2) 50%, var(--bg-3) 100%);
6401
+ background-size: 200% 100%;
6402
+ }
6403
+ }
6404
+ @keyframes cm-skel-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
5575
6405
 
5576
6406
  /* ForumView — cm-forum / cm-forum-* */
5577
6407
  .ds-247420 .cm-forum { display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--bg-1, var(--bg-2)); color: var(--fg); }
5578
- .ds-247420 .cm-forum-toolbar { display: flex; gap: var(--space-2); align-items: center; padding: var(--space-2); border-bottom: var(--bw-hair) solid var(--rule); }
6408
+ .ds-247420 .cm-forum-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; padding: var(--space-2); border-bottom: var(--bw-hair) solid var(--rule); }
5579
6409
  .ds-247420 .cm-forum-search { flex: 1; padding: var(--space-1) var(--space-2); border: var(--bw-hair) solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); }
5580
6410
  .ds-247420 .cm-forum-sort { padding: var(--space-1); border: var(--bw-hair) solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); }
5581
6411
  .ds-247420 .cm-forum-new { padding: var(--space-1) var(--space-2); border: none; border-radius: var(--r-1); background: var(--accent); color: var(--accent-fg); cursor: pointer; }
@@ -5768,13 +6598,13 @@
5768
6598
  position: absolute; right: 16px; bottom: 12px; z-index: 3;
5769
6599
  display: none; align-items: center; gap: .35em;
5770
6600
  padding: .4em .8em; font: inherit; font-size: var(--fs-tiny); cursor: pointer;
5771
- border-radius: 999px; border: var(--bw-hair) solid var(--rule);
6601
+ border-radius: var(--r-pill); border: var(--bw-hair) solid var(--rule);
5772
6602
  background: var(--bg-2); color: var(--fg-2, var(--fg));
5773
6603
  box-shadow: 0 2px 8px color-mix(in srgb, var(--fg) 14%, transparent);
5774
6604
  }
5775
6605
  .ds-247420 .agentchat-jump.show { display: inline-flex; }
5776
6606
  .ds-247420 .agentchat-jump:hover { background: var(--bg-3); }
5777
- .ds-247420 .agentchat-jump:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
6607
+ .ds-247420 .agentchat-jump:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
5778
6608
 
5779
6609
  /* Streaming caret: a thin blinking bar at the live edge of an assistant turn. */
5780
6610
  .ds-247420 .chat-stream-caret {
@@ -5796,7 +6626,7 @@
5796
6626
  }
5797
6627
  .ds-247420 .chat-msg-action-label { font-size: var(--fs-tiny); }
5798
6628
  .ds-247420 .chat-msg-action:hover { background: var(--bg-2); color: var(--fg); }
5799
- .ds-247420 .chat-msg-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; opacity: 1; }
6629
+ .ds-247420 .chat-msg-action:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; opacity: 1; }
5800
6630
 
5801
6631
  /* Empty state: a fresh thread is an invitation, not a void. */
5802
6632
  .ds-247420 .agentchat-empty {
@@ -5824,7 +6654,7 @@
5824
6654
  font: inherit;
5825
6655
  font-size: var(--fs-tiny);
5826
6656
  padding: .4em .8em;
5827
- border-radius: 999px;
6657
+ border-radius: var(--r-pill);
5828
6658
  border: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
5829
6659
  background: color-mix(in srgb, var(--fg) 5%, transparent);
5830
6660
  color: var(--fg-2, var(--fg));
@@ -5863,7 +6693,7 @@
5863
6693
  font-family: var(--ff-body); font-size: var(--fs-tiny);
5864
6694
  }
5865
6695
  .ds-247420 .agentchat-install-copy:hover { background: var(--bg-3); color: var(--fg); }
5866
- .ds-247420 .agentchat-install-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
6696
+ .ds-247420 .agentchat-install-copy:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
5867
6697
  .ds-247420 .agentchat-install-actions { display: flex; justify-content: flex-start; }
5868
6698
 
5869
6699
  /* Host-supplied transcript export actions riding the controls row. */
@@ -5874,7 +6704,7 @@
5874
6704
  font-family: var(--ff-body); font-size: var(--fs-tiny);
5875
6705
  }
5876
6706
  .ds-247420 .agentchat-export-act:hover { background: var(--bg-2); color: var(--fg); }
5877
- .ds-247420 .agentchat-export-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
6707
+ .ds-247420 .agentchat-export-act:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
5878
6708
 
5879
6709
  /* "working" tail: a long silent tool call shouldn't read as frozen. */
5880
6710
  .ds-247420 .agentchat-working {
@@ -6004,7 +6834,7 @@
6004
6834
  /* Rail filter uses the shared .ds-search-input primitive (provides bg/border/
6005
6835
  radius/focus-ring); only the rail layout + touch floor live here. */
6006
6836
  .ds-247420 .ds-session-head .ds-search-input { order: 1; flex: 1 1 auto; min-width: 0; min-height: 36px; padding: 0 10px; }
6007
- .ds-247420 .ds-session-new:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
6837
+ .ds-247420 .ds-session-new:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
6008
6838
  /* Touch floor (must FOLLOW the base rules - same specificity, order decides). */
6009
6839
  @media (pointer: coarse) {
6010
6840
  .ds-247420 .ds-session-new { width: 44px; min-height: 44px; }
@@ -6023,10 +6853,10 @@
6023
6853
  cursor: pointer; text-align: left; color: var(--fg);
6024
6854
  }
6025
6855
  .ds-247420 .ds-session-row:hover { background: var(--bg-2); }
6026
- .ds-247420 .ds-session-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
6856
+ .ds-247420 .ds-session-row:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
6027
6857
  .ds-247420 .ds-session-row.active { background: var(--accent-tint); box-shadow: inset 2px 0 0 var(--accent); }
6028
6858
  .ds-247420 .ds-session-row.rail-green::before, .ds-247420 .ds-session-row.rail-purple::before, .ds-247420 .ds-session-row.rail-flame::before {
6029
- content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px; border-radius: 3px;
6859
+ content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 3px; border-radius: var(--r-hair);
6030
6860
  }
6031
6861
  /* Rail tones MUST match .row.rail-* in app-shell.css so the same semantic state
6032
6862
  reads as one colour across the conversation list and content rows. */
@@ -6117,7 +6947,7 @@
6117
6947
  }
6118
6948
  .ds-247420 .chat-code-block:hover .chat-code-copy, .ds-247420 .chat-code-block:focus-within .chat-code-copy { opacity: 1; }
6119
6949
  .ds-247420 .chat-code-copy.is-copied { color: var(--accent-ink); border-color: var(--accent); }
6120
- .ds-247420 .chat-code-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; opacity: 1; }
6950
+ .ds-247420 .chat-code-copy:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; opacity: 1; }
6121
6951
  /* Head-placed copy (structured CodeNode + FilePreviewCode) is always visible. */
6122
6952
  .ds-247420 .chat-code-head .spread { flex: 1; }
6123
6953
  .ds-247420 .chat-code-copy-head { position: static; opacity: 1; }
@@ -6157,6 +6987,12 @@
6157
6987
  font-family: var(--ff-mono); font-size: var(--fs-tiny);
6158
6988
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
6159
6989
  }
6990
+ /* Below ~480px a single nowrap line silently truncates most of the agent /
6991
+ model / cwd context (no way to recover it - no title attr on the container,
6992
+ only on individual bits). Let it wrap instead of clipping. */
6993
+ @media (max-width: 480px) {
6994
+ .ds-247420 .chat-composer-context { white-space: normal; overflow: visible; text-overflow: clip; }
6995
+ }
6160
6996
  .ds-247420 button.chat-composer-context { cursor: pointer; }
6161
6997
  .ds-247420 button.chat-composer-context:hover { color: var(--fg-2); }
6162
6998
  .ds-247420 button.chat-composer-context:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
@@ -6206,7 +7042,7 @@
6206
7042
  cursor: pointer; font-family: var(--ff-body); font-size: var(--fs-tiny);
6207
7043
  }
6208
7044
  .ds-247420 .ds-dash-errors-toggle.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
6209
- .ds-247420 .ds-dash-errors-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7045
+ .ds-247420 .ds-dash-errors-toggle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6210
7046
 
6211
7047
  /* --- C3: per-card select checkbox. --- */
6212
7048
  .ds-247420 .ds-dash-select {
@@ -6216,7 +7052,7 @@
6216
7052
  font-family: var(--ff-mono); font-size: var(--fs-sm);
6217
7053
  }
6218
7054
  .ds-247420 .ds-dash-select[aria-checked="true"] { color: var(--accent-ink); }
6219
- .ds-247420 .ds-dash-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7055
+ .ds-247420 .ds-dash-select:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6220
7056
 
6221
7057
  /* --- C5: active dashboard card (current conversation). --- */
6222
7058
  .ds-247420 .ds-dash-card.is-active { box-shadow: inset 2px 0 0 var(--accent); }
@@ -6238,7 +7074,7 @@
6238
7074
 
6239
7075
  /* --- E1: inline file preview pane (split view, non-modal). --- */
6240
7076
  .ds-247420 .ds-preview-pane { display: flex; flex-direction: column; min-height: 0; height: 100%; overflow: hidden; }
6241
- .ds-247420 .ds-preview-pane:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
7077
+ .ds-247420 .ds-preview-pane:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
6242
7078
  .ds-247420 .ds-preview-pane .ds-preview-body { flex: 1; min-height: 0; overflow: auto; }
6243
7079
  .ds-247420 .ds-preview-pane-empty { align-items: center; justify-content: center; color: var(--fg-3); font-size: var(--fs-sm); }
6244
7080
  .ds-247420 .ds-preview-code-wrap { display: flex; flex-direction: column; min-height: 0; }
@@ -6255,7 +7091,7 @@
6255
7091
  border-radius: var(--r-1); background: var(--bg-2); color: var(--fg-2); cursor: pointer;
6256
7092
  font-family: var(--ff-body); font-size: var(--fs-tiny);
6257
7093
  }
6258
- .ds-247420 .ds-file-more-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7094
+ .ds-247420 .ds-file-more-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6259
7095
  /* --- D3: locked/no-access file row. --- */
6260
7096
  .ds-247420 .ds-file-row.is-locked { opacity: .6; }
6261
7097
 
@@ -6266,8 +7102,9 @@
6266
7102
  background: none; color: var(--fg-3); cursor: pointer;
6267
7103
  font-family: var(--ff-body); font-size: var(--fs-tiny);
6268
7104
  }
7105
+ .ds-247420 .ds-roots-tab:hover { background: var(--bg-2); color: var(--fg); }
6269
7106
  .ds-247420 .ds-roots-tab.active { background: var(--bg); color: var(--fg); }
6270
- .ds-247420 .ds-roots-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7107
+ .ds-247420 .ds-roots-tab:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6271
7108
 
6272
7109
  /* --- H4: touch targets. On a coarse pointer / narrow screen the hover-revealed
6273
7110
  action rows are made permanently visible and small controls floor to 44px so
@@ -6299,7 +7136,7 @@
6299
7136
  color: var(--fg-3); font-family: var(--ff-body); font-size: var(--fs-micro);
6300
7137
  }
6301
7138
  .ds-247420 .ds-session-meta-copy:hover { background: var(--bg-3); color: var(--fg); }
6302
- .ds-247420 .ds-session-meta-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7139
+ .ds-247420 .ds-session-meta-copy:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6303
7140
  @media (pointer: coarse), (max-width: 640px) {
6304
7141
  .ds-247420 .ds-session-meta-copy { min-height: 44px; min-width: 44px; }
6305
7142
  }
@@ -6327,7 +7164,7 @@
6327
7164
  }
6328
7165
 
6329
7166
  /* Drag-over ring: token accent, never a hex. */
6330
- .ds-247420 .chat-composer.dragover { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-2); }
7167
+ .ds-247420 .chat-composer.dragover { outline: 2px solid var(--accent-ink); outline-offset: -2px; border-radius: var(--r-2); }
6331
7168
 
6332
7169
  /* Per-bit composer context: only the bit that owns a control is a button. */
6333
7170
  .ds-247420 .chat-composer-context-bit {
@@ -6367,7 +7204,8 @@
6367
7204
  border-radius: var(--r-1); background: var(--bg-2); color: var(--fg-2); cursor: pointer;
6368
7205
  font-family: var(--ff-body); font-size: var(--fs-tiny);
6369
7206
  }
6370
- .ds-247420 .agentchat-earlier-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7207
+ .ds-247420 .agentchat-earlier-btn:hover { background: var(--bg-2); color: var(--fg); }
7208
+ .ds-247420 .agentchat-earlier-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6371
7209
  @media (pointer: coarse) {
6372
7210
  .ds-247420 .agentchat-earlier-btn { min-height: 44px; }
6373
7211
  }
@@ -6475,7 +7313,7 @@
6475
7313
  }
6476
7314
  .ds-247420 .chat-msg .chat-tool .chat-tool-head::-webkit-details-marker { display: none; }
6477
7315
  .ds-247420 .chat-msg .chat-tool .chat-tool-head:hover { background: var(--bg-2); }
6478
- .ds-247420 .chat-msg .chat-tool .chat-tool-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
7316
+ .ds-247420 .chat-msg .chat-tool .chat-tool-head:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
6479
7317
  .ds-247420 .chat-tool-icon { display: inline-flex; color: var(--fg-3); }
6480
7318
  .ds-247420 .chat-tool-name { font-family: var(--ff-mono); font-weight: 600; color: var(--fg); }
6481
7319
  .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; }
@@ -6492,11 +7330,14 @@
6492
7330
  neutral pill and from the accent-toned running pill (--success = green-2). */
6493
7331
  .ds-247420 .chat-msg .chat-tool.tool-done .chat-tool-status { color: var(--success); background: color-mix(in oklab, var(--success) 12%, transparent); }
6494
7332
  .ds-247420 .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); }
7333
+ /* details' intrinsic min-content sizing: an unbroken token in the pre must not
7334
+ widen the tool card past the bubble column. */
7335
+ .ds-247420 .chat-msg .chat-tool, .ds-247420 .chat-tool-body, .ds-247420 .chat-tool-section { min-width: 0; max-width: 100%; }
6495
7336
  .ds-247420 .chat-tool-section { display: flex; flex-direction: column; gap: var(--space-1); }
6496
7337
  .ds-247420 .chat-tool-section-label { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); font-size: var(--fs-tiny); font-weight: 600; text-transform: uppercase; letter-spacing: var(--tr-caps); color: var(--fg-3); }
6497
7338
  .ds-247420 .chat-tool-copy { position: static; opacity: 0; }
6498
7339
  .ds-247420 .chat-tool-section:hover .chat-tool-copy, .ds-247420 .chat-tool-section:focus-within .chat-tool-copy { opacity: 1; }
6499
- .ds-247420 .chat-tool-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; opacity: 1; }
7340
+ .ds-247420 .chat-tool-copy:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; opacity: 1; }
6500
7341
  .ds-247420 .chat-tool-pre { margin: 0; padding: var(--space-2); background: var(--bg-2); border-radius: var(--r-1); font-family: var(--ff-mono); font-size: var(--fs-tiny); line-height: 1.45; overflow-x: auto; max-height: 320px; overflow-y: auto; }
6501
7342
  .ds-247420 .chat-tool-pre.is-error { color: var(--flame); }
6502
7343
  .ds-247420 .chat-tool-pre.chat-tool-empty { color: var(--fg-3); }
@@ -6559,10 +7400,11 @@
6559
7400
  .ds-247420 .ds-dash-breakdown .seg.is-idle::before { background: transparent; box-shadow: inset 0 0 0 1px var(--stale), inset 0 0 0 3px var(--bg); }
6560
7401
  .ds-247420 .ds-dash-stream-disc { display: inline-flex; align-items: center; gap: var(--space-1); }
6561
7402
  .ds-247420 .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); }
6562
- .ds-247420 .ds-dash-selectall:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
7403
+ .ds-247420 .ds-dash-selectall:hover { color: var(--fg); }
7404
+ .ds-247420 .ds-dash-selectall:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6563
7405
  .ds-247420 .ds-dash-clear { background: none; border: none; color: var(--fg-3); cursor: pointer; font-size: var(--fs-tiny); text-decoration: underline dotted; padding: var(--space-1); }
6564
7406
  .ds-247420 .ds-dash-clear:hover { color: var(--fg); }
6565
- .ds-247420 .ds-dash-clear:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: var(--r-1); }
7407
+ .ds-247420 .ds-dash-clear:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; border-radius: var(--r-1); }
6566
7408
 
6567
7409
  /* Conversation-rail loading skeleton (cold ccsniff walk). */
6568
7410
  .ds-247420 .ds-session-row-skeleton { display: flex; flex-direction: column; gap: 6px; padding: var(--space-2) var(--space-3); }
@@ -6732,6 +7574,29 @@
6732
7574
  .ds-247420 .ds-ep-toolbar-trailing { margin-left: auto; }
6733
7575
  .ds-247420 .ds-ep-toolbar-center { flex: 1; min-width: 0; }
6734
7576
 
7577
+ /* ToolbarRow — flat wrapping action row, no slot structure. */
7578
+ .ds-247420 .ds-ep-toolbar-row {
7579
+ display: flex; gap: var(--space-2, 8px); align-items: center; flex-wrap: wrap;
7580
+ margin-bottom: var(--space-2-5, 10px);
7581
+ }
7582
+ .ds-247420 .ds-ep-toolbar-row input,
7583
+ .ds-247420 .ds-ep-toolbar-row select,
7584
+ .ds-247420 .ds-ep-toolbar-row textarea {
7585
+ background: var(--panel-2, var(--bg-2));
7586
+ border: 1px solid var(--rule);
7587
+ color: var(--panel-text, var(--fg));
7588
+ padding: var(--space-1-5, 5px) var(--space-2-5, 10px);
7589
+ border-radius: var(--r-1, 4px);
7590
+ font-size: var(--fs-tiny, 12px);
7591
+ font-family: inherit;
7592
+ }
7593
+ .ds-247420 .ds-ep-toolbar-row input { flex: 1; min-width: 140px; }
7594
+ .ds-247420 .ds-ep-toolbar-row input:focus-visible,
7595
+ .ds-247420 .ds-ep-toolbar-row select:focus-visible,
7596
+ .ds-247420 .ds-ep-toolbar-row textarea:focus-visible {
7597
+ outline: none; border-color: var(--accent);
7598
+ }
7599
+
6735
7600
  /* Tabs */
6736
7601
  .ds-247420 .ds-ep-tabs { display: flex; flex-direction: column; min-height: 0; height: 100%; }
6737
7602
  .ds-247420 .ds-ep-tabs-head {
@@ -6780,7 +7645,7 @@
6780
7645
  overflow: auto;
6781
7646
  }
6782
7647
  .ds-247420 .ds-ep-tree-item { display: flex; flex-direction: column; }
6783
- .ds-247420 .ds-ep-tree-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
7648
+ .ds-247420 .ds-ep-tree-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
6784
7649
  .ds-247420 .ds-ep-tree-row {
6785
7650
  display: flex; align-items: center; gap: 6px;
6786
7651
  padding: 4px 8px 4px 0;
@@ -6907,6 +7772,45 @@
6907
7772
  .ds-247420 .ds-ep-propfield.block .ds-ep-btngrp { width: 100%; }
6908
7773
  .ds-247420 .ds-ep-propfield.block .ds-ep-btngrp-btn { flex: 1 1 0; text-align: center; }
6909
7774
 
7775
+ /* PropertyGridRow — bordered-row variant for a list of independently-editable
7776
+ records (each record its own bottom-divided block, last one flush). */
7777
+ .ds-247420 .ds-ep-propgrid-row {
7778
+ border-bottom: 1px solid var(--rule);
7779
+ padding: var(--space-2, 8px) 0;
7780
+ }
7781
+ .ds-247420 .ds-ep-propgrid-row:last-child { border-bottom: none; }
7782
+
7783
+ /* InlineEditableField — transparent-until-focus input, error state exposed
7784
+ both visually (danger border) and semantically (aria-invalid, read by the
7785
+ caller's own error text via aria-describedby if wired).
7786
+ Specificity note: `.ds-ep-propfield-value input` (descendant combinator,
7787
+ 2 classes + 1 tag = (0,2,1) specificity) sets a visible border on every
7788
+ input nested in a PropertyField -- the exact idiom InlineEditableField is
7789
+ meant to be dropped into. A bare `input.ds-ep-inline-input` is only
7790
+ (0,1,1) and loses; `:where(.ds-ep-propfield-value, .ds-ep-inline-standalone)`
7791
+ is intentionally NOT used here because :where() has zero specificity and
7792
+ would still lose. Instead the selector repeats .ds-ep-inline-input twice
7793
+ (a valid, standard way to bump specificity by one class without adding an
7794
+ ambient wrapper dependency) to reliably out-rank the PropertyField rule
7795
+ regardless of nesting context. */
7796
+ .ds-247420 .ds-ep-inline-input.ds-ep-inline-input {
7797
+ background: transparent;
7798
+ border: 1px solid transparent;
7799
+ color: inherit; font: inherit;
7800
+ width: 100%;
7801
+ border-radius: var(--r-1, 4px);
7802
+ padding: var(--space-hair, 2px) var(--space-1, 4px);
7803
+ }
7804
+ .ds-247420 .ds-ep-inline-input.ds-ep-inline-input:focus-visible {
7805
+ outline: none;
7806
+ border-color: var(--accent);
7807
+ background: var(--panel-2, var(--bg-2));
7808
+ }
7809
+ .ds-247420 .ds-ep-inline-input.ds-ep-inline-input.has-error,
7810
+ .ds-247420 .ds-ep-inline-input.ds-ep-inline-input[aria-invalid="true"] {
7811
+ border-color: var(--danger);
7812
+ }
7813
+
6910
7814
  /* Flush dense action bar docked at a panel bottom (inspector Edit/Delete etc.).
6911
7815
  Compact buttons, square-ish, bordered top — not big floating pills. */
6912
7816
  .ds-247420 .ds-ep-actionbar {
@@ -6938,6 +7842,103 @@
6938
7842
  .ds-247420 .ds-ep-toolbar button:not(.ds-ep-btngrp-btn) { min-height: 36px; height: 36px; }
6939
7843
  }
6940
7844
 
7845
+ /* Pager */
7846
+ .ds-247420 .ds-ep-pager {
7847
+ display: flex; align-items: center; gap: var(--space-1-75, 6px);
7848
+ margin-top: var(--space-2, 8px);
7849
+ font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
7850
+ color: var(--panel-text-3, var(--fg-3));
7851
+ }
7852
+ .ds-247420 .ds-ep-pager-btn {
7853
+ appearance: none; cursor: pointer;
7854
+ background: var(--panel-2, var(--bg-2));
7855
+ border: 1px solid var(--rule);
7856
+ color: var(--panel-text, var(--fg));
7857
+ padding: var(--space-half, 3px) var(--space-2-5, 10px);
7858
+ border-radius: var(--r-1, 4px);
7859
+ font: inherit;
7860
+ }
7861
+ .ds-247420 .ds-ep-pager-btn:hover:not([disabled]) { background: color-mix(in oklab, var(--accent) 10%, transparent); }
7862
+ .ds-247420 .ds-ep-pager-btn:disabled { opacity: 0.4; cursor: default; }
7863
+ .ds-247420 .ds-ep-pager-label { white-space: nowrap; }
7864
+
7865
+ /* JsonViewer */
7866
+ .ds-247420 .ds-ep-json {
7867
+ font-size: var(--fs-tiny, 12px);
7868
+ font-family: var(--ff-mono, ui-monospace, Consolas, monospace);
7869
+ white-space: pre-wrap; word-break: break-all;
7870
+ background: var(--panel-2, var(--bg-2));
7871
+ color: var(--panel-text, var(--fg));
7872
+ padding: var(--space-2, 8px);
7873
+ border-radius: var(--r-1, var(--r-2, 4px));
7874
+ max-height: 300px;
7875
+ overflow-y: auto;
7876
+ margin: 0;
7877
+ }
7878
+ .ds-247420 .ds-ep-json-empty {
7879
+ color: var(--panel-text-3, var(--fg-3));
7880
+ white-space: normal;
7881
+ text-align: center;
7882
+ }
7883
+ /* JsonViewer syntax tokens (mode:'highlight'/'tree') — semantic theme tokens
7884
+ only (retuned per-theme in colors_and_type.css); fallbacks chain to
7885
+ coarser tokens, never a raw literal, so standalone kits stay themed. */
7886
+ .ds-247420 .ds-ep-json-k { color: var(--sky, var(--accent)); }
7887
+ .ds-247420 .ds-ep-json-s { color: var(--green-2, var(--green)); }
7888
+ .ds-247420 .ds-ep-json-n { color: var(--flame, var(--warn)); }
7889
+ .ds-247420 .ds-ep-json-b { color: var(--purple-2, var(--purple)); }
7890
+ .ds-247420 .ds-ep-json-z { color: var(--panel-text-3, var(--fg-3)); font-style: italic; }
7891
+ /* Collapsible tree mode — native details/summary, indent guides on children. */
7892
+ .ds-247420 .ds-ep-json-tree { white-space: normal; }
7893
+ .ds-247420 .ds-ep-json-kids {
7894
+ padding-left: var(--space-3-5, 14px);
7895
+ margin-left: var(--space-1, 4px);
7896
+ border-left: 1px solid var(--rule);
7897
+ }
7898
+ .ds-247420 .ds-ep-json-sum {
7899
+ cursor: pointer; user-select: none;
7900
+ list-style: none;
7901
+ border-radius: var(--r-1, 4px);
7902
+ }
7903
+ .ds-247420 .ds-ep-json-sum::-webkit-details-marker { display: none; }
7904
+ .ds-247420 .ds-ep-json-sum::before {
7905
+ content: '+';
7906
+ display: inline-block; width: var(--space-3, 12px);
7907
+ color: var(--panel-text-3, var(--fg-3));
7908
+ }
7909
+ .ds-247420 .ds-ep-json-node[open] > .ds-ep-json-sum::before { content: '-'; }
7910
+ .ds-247420 .ds-ep-json-sum:hover { background: color-mix(in oklab, var(--accent) 8%, transparent); }
7911
+ .ds-247420 .ds-ep-json-sum:focus-visible {
7912
+ outline: 2px solid var(--accent-ink);
7913
+ outline-offset: -2px;
7914
+ }
7915
+ .ds-247420 .ds-ep-json-tag {
7916
+ margin-left: var(--space-1, 4px);
7917
+ font-size: var(--fs-micro, 11px);
7918
+ color: var(--panel-text-3, var(--fg-3));
7919
+ }
7920
+ .ds-247420 .ds-ep-json-leaf { padding-left: var(--space-3, 12px); word-break: break-all; }
7921
+ /* Copy affordance (copyable:true) — floats over the viewer's top-right. */
7922
+ .ds-247420 .ds-ep-json-wrap { position: relative; }
7923
+ .ds-247420 .ds-ep-json-copy {
7924
+ position: absolute; top: var(--space-1-75, 6px); right: var(--space-1-75, 6px); z-index: 1;
7925
+ appearance: none; cursor: pointer;
7926
+ background: var(--panel-1, var(--bg-1));
7927
+ border: 1px solid var(--rule);
7928
+ color: var(--panel-text-2, var(--fg-2));
7929
+ font: var(--fs-micro, 11px)/1 var(--ff-mono, monospace);
7930
+ padding: var(--space-half, 3px) var(--space-2, 8px);
7931
+ border-radius: var(--r-1, 4px);
7932
+ opacity: 0.75;
7933
+ }
7934
+ .ds-247420 .ds-ep-json-copy:hover { opacity: 1; border-color: var(--accent); }
7935
+ .ds-247420 .ds-ep-json-copy.copied { color: var(--green-2, var(--green)); border-color: var(--green-2, var(--green)); opacity: 1; }
7936
+ .ds-247420 .ds-ep-json-copy:focus-visible {
7937
+ outline: 2px solid var(--accent-ink);
7938
+ outline-offset: 2px;
7939
+ opacity: 1;
7940
+ }
7941
+
6941
7942
  /* Dock — 3x3 grid for in-engine overlay (canvas pass-through center) */
6942
7943
  .ds-247420 .ds-ep-dock {
6943
7944
  display: grid;
@@ -7042,6 +8043,11 @@
7042
8043
  .ds-247420 .ds-ep-ctxmenu {
7043
8044
  position: absolute;
7044
8045
  min-width: 180px;
8046
+ max-width: calc(100vw - 8px);
8047
+ max-height: calc(100vh - 8px);
8048
+ max-height: calc(100dvh - 8px);
8049
+ overflow-y: auto;
8050
+ overscroll-behavior: contain;
7045
8051
  background: var(--panel-1, var(--panel-bg));
7046
8052
  color: var(--panel-text, var(--fg-text));
7047
8053
  border: 1px solid var(--rule);
@@ -7090,7 +8096,7 @@
7090
8096
  }
7091
8097
  .ds-247420 .ds-ep-drawer.side-left { left: 0; top: 0; bottom: 0; width: 86vw; max-width: 320px; }
7092
8098
  .ds-247420 .ds-ep-drawer.side-right { right: 0; top: 0; bottom: 0; width: 86vw; max-width: 320px; }
7093
- .ds-247420 .ds-ep-drawer.side-bottom { left: 0; right: 0; bottom: 0; max-height: 80vh; border-top-left-radius: 12px; border-top-right-radius: 12px; }
8099
+ .ds-247420 .ds-ep-drawer.side-bottom { left: 0; right: 0; bottom: 0; max-height: 80vh; max-height: 80dvh; border-top-left-radius: 12px; border-top-right-radius: 12px; }
7094
8100
  @media (min-width: 768px) {
7095
8101
  .ds-247420 .ds-ep-drawer.side-left, .ds-247420 .ds-ep-drawer.side-right { width: 360px; max-width: 360px; }
7096
8102
  }
@@ -7102,7 +8108,7 @@
7102
8108
  position: fixed; inset: 0; z-index: 9500;
7103
8109
  background: var(--scrim-strong);
7104
8110
  display: flex; align-items: center; justify-content: center;
7105
- padding: 16px;
8111
+ padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
7106
8112
  }
7107
8113
  .ds-247420 .ds-ep-dialog {
7108
8114
  background: var(--panel-1, var(--panel-bg));
@@ -7111,7 +8117,9 @@
7111
8117
  border-radius: var(--r-2, 10px);
7112
8118
  box-shadow: var(--shadow-overlay);
7113
8119
  min-width: 280px; max-width: min(560px, 100%);
7114
- max-height: 90vh; overflow: auto;
8120
+ max-height: 90vh;
8121
+ max-height: min(90dvh, calc(100dvh - 32px));
8122
+ overflow: auto;
7115
8123
  display: flex; flex-direction: column;
7116
8124
  outline: none;
7117
8125
  }
@@ -7129,12 +8137,15 @@
7129
8137
  background: var(--panel-2, transparent);
7130
8138
  color: inherit; font: inherit; cursor: pointer;
7131
8139
  }
8140
+ .ds-247420 .ds-ep-dialog-btn:hover { background: var(--panel-3, var(--bg-3)); }
7132
8141
  .ds-247420 .ds-ep-dialog-btn.kind-primary {
7133
8142
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
7134
8143
  }
8144
+ .ds-247420 .ds-ep-dialog-btn.kind-primary:hover { filter: brightness(1.08); }
7135
8145
  .ds-247420 .ds-ep-dialog-btn.kind-danger {
7136
8146
  background: var(--danger); color: var(--on-accent); border-color: var(--danger);
7137
8147
  }
8148
+ .ds-247420 .ds-ep-dialog-btn.kind-danger:hover { filter: brightness(1.1); }
7138
8149
 
7139
8150
  /* ---------------------------------------------------------------
7140
8151
  Toast
@@ -7177,8 +8188,9 @@
7177
8188
  .ds-247420 .ds-ep-btngrp-btn:focus-visible,
7178
8189
  .ds-247420 .ds-ep-ctxmenu-item:focus-visible,
7179
8190
  .ds-247420 .ds-ep-resize:focus-visible,
7180
- .ds-247420 .ds-ep-dialog-btn:focus-visible {
7181
- outline: 2px solid var(--accent);
8191
+ .ds-247420 .ds-ep-dialog-btn:focus-visible,
8192
+ .ds-247420 .ds-ep-pager-btn:focus-visible {
8193
+ outline: 2px solid var(--accent-ink);
7182
8194
  outline-offset: 2px;
7183
8195
  }
7184
8196
 
@@ -7190,7 +8202,8 @@
7190
8202
  .ds-247420 .ds-ep-btngrp-btn,
7191
8203
  .ds-247420 .ds-ep-ctxmenu-item,
7192
8204
  .ds-247420 .ds-ep-dialog-btn,
7193
- .ds-247420 .ds-ep-tree-row {
8205
+ .ds-247420 .ds-ep-tree-row,
8206
+ .ds-247420 .ds-ep-pager-btn {
7194
8207
  min-height: 44px;
7195
8208
  padding-top: 10px;
7196
8209
  padding-bottom: 10px;
@@ -7229,7 +8242,7 @@
7229
8242
  .ds-247420 .ds-ep-iconbtn:focus-visible,
7230
8243
  .ds-247420 .ds-ep-iconbtn-group button:focus-visible,
7231
8244
  .ds-247420 .ds-ep-resize:focus-visible {
7232
- outline: 2px solid var(--accent);
8245
+ outline: 2px solid var(--accent-ink);
7233
8246
  outline-offset: 2px;
7234
8247
  border-radius: var(--r-1);
7235
8248
  }
@@ -7258,7 +8271,7 @@
7258
8271
  cursor: inherit;
7259
8272
  }
7260
8273
  .ds-247420 .ds-check:focus-visible, .ds-247420 .ds-radio:focus-visible {
7261
- outline: 2px solid var(--accent);
8274
+ outline: 2px solid var(--accent-ink);
7262
8275
  outline-offset: 2px;
7263
8276
  }
7264
8277
 
@@ -7285,6 +8298,7 @@
7285
8298
  padding: 0;
7286
8299
  flex-shrink: 0;
7287
8300
  }
8301
+ .ds-247420 .ds-toggle:hover { border-color: var(--rule-strong, var(--fg-3)); }
7288
8302
  .ds-247420 .ds-toggle-knob {
7289
8303
  position: absolute;
7290
8304
  top: 1px; left: 1px;
@@ -7302,7 +8316,7 @@
7302
8316
  transform: translateX(20px);
7303
8317
  }
7304
8318
  .ds-247420 .ds-toggle:focus-visible {
7305
- outline: 2px solid var(--accent);
8319
+ outline: 2px solid var(--accent-ink);
7306
8320
  outline-offset: 2px;
7307
8321
  }
7308
8322
  .ds-247420 .ds-toggle:disabled { cursor: not-allowed; }
@@ -7387,6 +8401,11 @@
7387
8401
  padding: 0;
7388
8402
  outline: none;
7389
8403
  min-width: 160px;
8404
+ max-width: calc(100vw - 8px);
8405
+ max-height: calc(100vh - 8px);
8406
+ max-height: calc(100dvh - 8px);
8407
+ overflow-y: auto;
8408
+ overscroll-behavior: contain;
7390
8409
  }
7391
8410
  @media (prefers-reduced-motion: no-preference) {
7392
8411
  .ds-247420 .ds-popover { transition: opacity 140ms ease, transform 140ms ease; }
@@ -7412,7 +8431,7 @@
7412
8431
  outline: none;
7413
8432
  }
7414
8433
  .ds-247420 .ds-dropdown-item:focus-visible {
7415
- outline: 2px solid var(--accent);
8434
+ outline: 2px solid var(--accent-ink);
7416
8435
  outline-offset: -2px;
7417
8436
  }
7418
8437
  .ds-247420 .ds-dropdown-item[aria-disabled="true"] {
@@ -7456,7 +8475,7 @@
7456
8475
  cursor: grab; font: 14px/1 var(--ff-mono, monospace); letter-spacing: -2px;
7457
8476
  touch-action: none; user-select: none;
7458
8477
  }
7459
- .ds-247420 .ds-reorder-handle:focus-visible { outline: 2px solid var(--focus-ring, var(--accent)); outline-offset: 2px; }
8478
+ .ds-247420 .ds-reorder-handle:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
7460
8479
  .ds-247420 .ds-reorder-handle:active { cursor: grabbing; }
7461
8480
  .ds-247420[data-dragging="true"] { opacity: 0.6; cursor: grabbing; transform: scale(0.98); }
7462
8481
  .ds-247420[data-drop-target-active="true"] {
@@ -7465,7 +8484,7 @@
7465
8484
  }
7466
8485
  .ds-247420 .ds-reorder-insertion-line {
7467
8486
  height: 2px; background: var(--focus-ring, var(--accent));
7468
- border-radius: 1px; animation: ds-insertion-in var(--dur-snap, 120ms) var(--ease, ease);
8487
+ border-radius: var(--r-hair); animation: ds-insertion-in var(--dur-snap, 120ms) var(--ease, ease);
7469
8488
  }
7470
8489
  @keyframes ds-insertion-in { from { transform: scaleX(0); opacity: 0; } to { transform: scaleX(1); opacity: 1; } }
7471
8490
  @media (prefers-reduced-motion: reduce) {
@@ -7532,6 +8551,7 @@
7532
8551
  color: var(--fg); font: inherit; text-align: left;
7533
8552
  border-radius: var(--r-1, 10px); cursor: pointer;
7534
8553
  }
8554
+ .ds-247420 .ov-cmd-item:hover { background: var(--panel-2, var(--rule)); }
7535
8555
  .ds-247420 .ov-cmd-item.is-active { background: var(--accent); color: var(--accent-fg); }
7536
8556
  .ds-247420 .ov-cmd-glyph { width: 18px; display: inline-flex; justify-content: center; flex-shrink: 0; }
7537
8557
  .ds-247420 .ov-cmd-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -7566,6 +8586,7 @@
7566
8586
  padding: var(--space-2, 8px); cursor: pointer; font-size: var(--fs-lg, 18px);
7567
8587
  border-bottom: 2px solid transparent;
7568
8588
  }
8589
+ .ds-247420 .ov-emoji-tab:hover { background: var(--bg-2); }
7569
8590
  .ds-247420 .ov-emoji-tab[aria-selected="true"] { border-bottom-color: var(--accent); background: var(--bg-2); }
7570
8591
  .ds-247420 .ov-emoji-grid { overflow: auto; max-height: 220px; padding: var(--space-2, 8px); }
7571
8592
  .ds-247420 .ov-emoji-grid-inner { display: grid; grid-template-columns: repeat(8, 1fr); gap: var(--space-1, 4px); }
@@ -7664,7 +8685,7 @@
7664
8685
  border: 1px solid var(--rule); border-radius: var(--r-1, 10px);
7665
8686
  padding: var(--space-1, 4px) var(--space-2, 8px); font: inherit;
7666
8687
  }
7667
- .ds-247420 .ov-set-control:focus-visible { outline: none; border-color: var(--accent); }
8688
+ .ds-247420 .ov-set-control:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; border-color: var(--accent-ink); }
7668
8689
  .ds-247420 input.ov-set-control[type="range"] { padding: 0; accent-color: var(--accent); }
7669
8690
  .ds-247420 .ov-set-toggle { width: 18px; height: 18px; accent-color: var(--accent); flex-shrink: 0; cursor: pointer; }
7670
8691
  .ds-247420 .ov-set-btn {
@@ -7694,6 +8715,7 @@
7694
8715
  .ds-247420 .ov-auth-x:hover { color: var(--fg); }
7695
8716
  .ds-247420 .ov-auth-tabs { display: flex; gap: var(--space-1); padding: var(--space-2) var(--space-3) 0; }
7696
8717
  .ds-247420 .ov-auth-tab { flex: 1; padding: var(--space-1) var(--space-2); border: 1px solid var(--rule); border-bottom: none; border-radius: var(--r-1) var(--r-1) 0 0; background: var(--bg-3); color: var(--fg-2, var(--fg)); cursor: pointer; }
8718
+ .ds-247420 .ov-auth-tab:hover { color: var(--fg); }
7697
8719
  .ds-247420 .ov-auth-tab.is-active { background: var(--bg-2); color: var(--fg); font-weight: 700; }
7698
8720
  .ds-247420 .ov-auth-body { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); }
7699
8721
  .ds-247420 .ov-auth-hint { margin: 0; font-size: var(--fs-0, 12px); color: var(--fg-2, var(--fg)); }
@@ -7759,8 +8781,8 @@
7759
8781
  background: var(--panel-2); cursor: pointer; flex-shrink: 0;
7760
8782
  }
7761
8783
  .ds-247420 .ds-input-color::-webkit-color-swatch-wrapper { padding: 2px; }
7762
- .ds-247420 .ds-input-color::-webkit-color-swatch { border: none; border-radius: 2px; }
7763
- .ds-247420 .ds-input-color:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
8784
+ .ds-247420 .ds-input-color::-webkit-color-swatch { border: none; border-radius: var(--r-hair); }
8785
+ .ds-247420 .ds-input-color:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
7764
8786
  .ds-247420 .ds-input-check {
7765
8787
  appearance: none; -webkit-appearance: none;
7766
8788
  width: 16px; height: 16px; flex-shrink: 0;
@@ -7773,7 +8795,7 @@
7773
8795
  width: 4px; height: 8px; border: solid var(--accent-fg);
7774
8796
  border-width: 0 2px 2px 0; transform: rotate(45deg);
7775
8797
  }
7776
- .ds-247420 .ds-input-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
8798
+ .ds-247420 .ds-input-check:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
7777
8799
 
7778
8800
  /* ---------------------------------------------------------------
7779
8801
  Tree drag-reparent affordance — clear drop target + dragging row.
@@ -7860,6 +8882,7 @@
7860
8882
  display: flex;
7861
8883
  flex-direction: column;
7862
8884
  height: 100vh;
8885
+ height: 100dvh;
7863
8886
  min-height: 0;
7864
8887
  overflow: hidden;
7865
8888
  }
@@ -7906,7 +8929,7 @@
7906
8929
  align-items: center;
7907
8930
  gap: 8px;
7908
8931
  padding: 6px 8px;
7909
- border-radius: 6px;
8932
+ border-radius: var(--r-0);
7910
8933
  color: var(--fg-2, color-mix(in oklab, var(--fg) 78%, transparent));
7911
8934
  text-decoration: none;
7912
8935
  font-size: var(--fs-sm, 14px);
@@ -7928,7 +8951,7 @@
7928
8951
  flex-shrink: 0;
7929
8952
  min-width: 18px;
7930
8953
  padding: 0 5px;
7931
- border-radius: 9px;
8954
+ border-radius: var(--r-1);
7932
8955
  background: var(--accent);
7933
8956
  color: var(--on-accent);
7934
8957
  font-size: 11px;
@@ -7961,6 +8984,40 @@
7961
8984
  align-content: start;
7962
8985
  }
7963
8986
 
8987
+ /* ============================================================
8988
+ Responsive — collapse the server+channel rail on narrow viewports.
8989
+ community-app builds its own hand-rolled .ca-app/.app-body/.ca-rail tree
8990
+ (not AppShell()), so it does not inherit AppShell's @container drawer CSS
8991
+ (keyed off .app/.app-side-shell, which .ca-app/.ca-rail never establish).
8992
+ Mirrors the .cm-channel-sidebar off-canvas idiom in community.css 1:1: same
8993
+ breakpoint, same translateX(-110%) + .open reveal, same :has() scrim — so
8994
+ the .ca-rail drawer driven by MobileHeader's hamburger (mobileMenuOpen in
8995
+ the adapter snapshot) behaves identically to the community kit's sidebar.
8996
+ ============================================================ */
8997
+ @media (max-width: 900px) {
8998
+ .ds-247420.ds-247420 .ca-rail {
8999
+ position: absolute;
9000
+ z-index: 20;
9001
+ top: 0; left: 0; bottom: 0;
9002
+ width: 240px; min-width: 240px;
9003
+ transform: translateX(-110%);
9004
+ transition: transform var(--dur-base, 240ms) var(--ease, ease);
9005
+ box-shadow: 2px 0 16px color-mix(in oklab, var(--ink, #000) 30%, transparent);
9006
+ }
9007
+ .ds-247420.ds-247420 .ca-rail.open { transform: translateX(0); }
9008
+ .ds-247420.ds-247420 .ca-app:has(.ca-rail.open) .app-main {
9009
+ position: relative;
9010
+ }
9011
+ .ds-247420.ds-247420 .ca-app:has(.ca-rail.open) .app-main::before {
9012
+ content: '';
9013
+ position: absolute;
9014
+ inset: 0;
9015
+ z-index: 15;
9016
+ background: color-mix(in oklab, var(--ink, #000) 40%, transparent);
9017
+ pointer-events: none;
9018
+ }
9019
+ }
9020
+
7964
9021
  /* app-surfaces.css */
7965
9022
  /* app-surfaces.css — agentgui application-surface styling.
7966
9023
  *
@@ -8117,15 +9174,19 @@
8117
9174
  display: flex; flex-direction: column; align-items: center; justify-content: center;
8118
9175
  gap: .4em; text-align: center; min-height: 50vh; color: var(--fg-3);
8119
9176
  }
8120
- .ds-247420 .history-empty-title { margin: 0; font-size: 1.05rem; color: var(--fg-2); }
9177
+ .ds-247420 .history-empty-title { margin: 0; font-size: var(--fs-lg); color: var(--fg-2); }
8121
9178
  .ds-247420 .history-empty-sub { margin: 0; max-width: 42ch; }
8122
9179
 
8123
- /* Settings: two-column on wide screens (backend + agents). */
9180
+ /* Settings: two-column on wide screens (backend + agents). Grid gap is the
9181
+ single source of rhythm between stacked Panels here - .panel's own
9182
+ margin-bottom would stack on top of the gap (32px + 24px = 56px, a break
9183
+ used nowhere else), so it's zeroed for direct grid children. */
8124
9184
  .ds-247420 .settings-grid {
8125
9185
  display: grid; gap: var(--space-4, 16px);
8126
9186
  grid-template-columns: minmax(0, 1fr);
8127
9187
  align-items: start;
8128
9188
  }
9189
+ .ds-247420 .settings-grid > .panel { margin-bottom: 0; }
8129
9190
  .ds-247420 .agentgui-main-settings .settings-grid { margin-top: 0; }
8130
9191
 
8131
9192
  /* The kit Chat head computes its own zero-padded count and ignores our sub
@@ -8172,7 +9233,7 @@
8172
9233
  }
8173
9234
 
8174
9235
  @media (prefers-reduced-motion: reduce) {
8175
- .ds-247420 .ds-event-list .row.event-flash { animation: none; outline: 2px solid var(--accent); }
9236
+ .ds-247420 .ds-event-list .row.event-flash { animation: none; outline: 2px solid var(--accent-ink); }
8176
9237
  }
8177
9238
 
8178
9239
  @media print {
@@ -8185,6 +9246,11 @@
8185
9246
  .ds-247420 .app, .ds-247420 .app-main, .ds-247420 .panel, .ds-247420 .chat, .ds-247420 .chat-thread {
8186
9247
  background: var(--paper) !important; color: var(--ink) !important; box-shadow: none !important;
8187
9248
  }
9249
+ /* Community surface: unclamp the fixed-height shell and hide the chrome so a
9250
+ transcript prints as flowing pages instead of one clipped viewport. */
9251
+ .ds-247420 .cm-shell { height: auto; overflow: visible; display: block; }
9252
+ .ds-247420 .cm-server-rail, .ds-247420 .cm-channel-sidebar, .ds-247420 .cm-member-list, .ds-247420 .cm-mobile-header, .ds-247420 .cm-voice-strip { display: none !important; }
9253
+ .ds-247420 .cm-main, .ds-247420 .cm-channel-list { overflow: visible; height: auto; }
8188
9254
  }
8189
9255
 
8190
9256
  /* gm-prose.css */
@@ -8236,13 +9302,14 @@
8236
9302
  top: 24px;
8237
9303
  align-self: start;
8238
9304
  max-height: calc(100vh - 48px);
9305
+ max-height: calc(100dvh - 48px);
8239
9306
  overflow-y: auto;
8240
9307
  overscroll-behavior: contain;
8241
9308
  margin: 0;
8242
9309
  max-width: 100%;
8243
9310
  padding: 18px 18px 18px 20px;
8244
9311
  background: var(--panel-1);
8245
- border-radius: 10px;
9312
+ border-radius: var(--r-1);
8246
9313
  box-shadow: var(--panel-shadow);
8247
9314
  scrollbar-width: thin;
8248
9315
  scrollbar-color: var(--panel-3) transparent;
@@ -8251,7 +9318,7 @@
8251
9318
  .ds-247420 #ds-article-host.has-toc > .toc::-webkit-scrollbar-track { background: transparent; }
8252
9319
  .ds-247420 #ds-article-host.has-toc > .toc::-webkit-scrollbar-thumb {
8253
9320
  background: var(--panel-3);
8254
- border-radius: 8px;
9321
+ border-radius: var(--r-0);
8255
9322
  border: 2px solid transparent;
8256
9323
  background-clip: padding-box;
8257
9324
  }
@@ -8287,7 +9354,7 @@
8287
9354
  .ds-247420 .cli {
8288
9355
  display: block;
8289
9356
  background: var(--panel-1);
8290
- border-radius: 8px;
9357
+ border-radius: var(--r-0);
8291
9358
  padding: 16px 20px;
8292
9359
  margin: 16px 0 28px 0;
8293
9360
  font-family: var(--ff-mono);
@@ -8299,7 +9366,7 @@
8299
9366
  white-space: pre-wrap;
8300
9367
  word-break: break-word;
8301
9368
  }
8302
- .ds-247420 .cli .cli-cmt {
9369
+ .ds-247420 .cli .ds-cli-comment {
8303
9370
  color: var(--panel-text-3);
8304
9371
  white-space: pre-wrap;
8305
9372
  word-break: break-word;
@@ -8307,20 +9374,20 @@
8307
9374
  padding: 3px 0;
8308
9375
  line-height: 1.6;
8309
9376
  }
8310
- .ds-247420 .cli .cli-cmt:empty::before { content: '\00a0'; }
8311
- .ds-247420 .cli .cli-line {
9377
+ .ds-247420 .cli .ds-cli-comment:empty::before { content: '\00a0'; }
9378
+ .ds-247420 .cli .ds-cli-row {
8312
9379
  display: flex;
8313
9380
  gap: 10px;
8314
9381
  padding: 3px 0;
8315
9382
  white-space: pre-wrap;
8316
9383
  word-break: break-word;
8317
9384
  }
8318
- .ds-247420 .cli .cli-line .prompt {
9385
+ .ds-247420 .cli .ds-cli-row .prompt {
8319
9386
  color: var(--panel-accent);
8320
9387
  flex: 0 0 auto;
8321
9388
  user-select: none;
8322
9389
  }
8323
- .ds-247420 .cli .cli-line .cmd {
9390
+ .ds-247420 .cli .ds-cli-row .cmd {
8324
9391
  color: var(--panel-text);
8325
9392
  flex: 1 1 auto;
8326
9393
  white-space: pre-wrap;
@@ -8348,7 +9415,7 @@
8348
9415
  padding: 14px 18px;
8349
9416
  margin: 8px 0;
8350
9417
  background: var(--panel-1);
8351
- border-radius: 6px;
9418
+ border-radius: var(--r-0);
8352
9419
  font-size: 13px;
8353
9420
  box-shadow: var(--panel-shadow);
8354
9421
  text-decoration: none;
@@ -8365,7 +9432,7 @@
8365
9432
  border: 1px solid var(--panel-3);
8366
9433
  font-size: 0.7rem;
8367
9434
  padding: 0.15rem 0.5rem;
8368
- border-radius: 3px;
9435
+ border-radius: var(--r-hair);
8369
9436
  font-family: var(--ff-mono);
8370
9437
  }
8371
9438
  .ds-247420 .ds-prose .gm-callout {
@@ -8466,7 +9533,7 @@
8466
9533
  }
8467
9534
  .ds-247420 .sp-loading-bar-track {
8468
9535
  height: 6px;
8469
- border-radius: 3px;
9536
+ border-radius: var(--r-hair);
8470
9537
  background: var(--bg-3);
8471
9538
  overflow: hidden;
8472
9539
  }
@@ -8502,8 +9569,9 @@
8502
9569
  }
8503
9570
  .ds-247420 .sp-hud-ammo {
8504
9571
  position: fixed;
8505
- bottom: 50px;
8506
- right: 20px;
9572
+ /* Fixed chrome clears notch/home-indicator on cutout devices. */
9573
+ bottom: calc(50px + env(safe-area-inset-bottom, 0px));
9574
+ right: calc(20px + env(safe-area-inset-right, 0px));
8507
9575
  font-size: 24px;
8508
9576
  font-weight: bold;
8509
9577
  color: var(--fg);
@@ -8512,7 +9580,7 @@
8512
9580
  .ds-247420 .sp-hud-ammo-reloading { color: var(--warn); }
8513
9581
  .ds-247420 .sp-hud-health {
8514
9582
  position: fixed;
8515
- bottom: 20px;
9583
+ bottom: calc(20px + env(safe-area-inset-bottom, 0px));
8516
9584
  left: 50%;
8517
9585
  transform: translateX(-50%);
8518
9586
  width: 200px;
@@ -8539,7 +9607,7 @@
8539
9607
  .ds-247420 .sp-hud-boost {
8540
9608
  position: fixed;
8541
9609
  top: 80px;
8542
- right: 20px;
9610
+ right: calc(20px + env(safe-area-inset-right, 0px));
8543
9611
  padding: 8px 16px;
8544
9612
  background: var(--accent);
8545
9613
  color: var(--accent-fg);
@@ -8572,6 +9640,11 @@
8572
9640
  border: 1px solid var(--bw-rule, var(--rule));
8573
9641
  border-radius: var(--r-2, 10px);
8574
9642
  color: var(--fg);
9643
+ /* Short landscape phones: keep lower controls reachable inside the card. */
9644
+ max-height: calc(100vh - 32px);
9645
+ max-height: calc(100dvh - 32px);
9646
+ overflow-y: auto;
9647
+ overscroll-behavior: contain;
8575
9648
  }
8576
9649
  .ds-247420 .sp-lobby-title {
8577
9650
  margin: 0;