anentrypoint-design 0.0.208 → 0.0.210
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app-shell.css +268 -93
- package/chat.css +111 -29
- package/colors_and_type.css +34 -1
- package/dist/247420.css +412 -123
- package/dist/247420.js +13 -13
- package/package.json +4 -2
- package/src/components/agent-chat.js +8 -2
- package/src/components/chat.js +26 -9
- package/src/components/content.js +28 -3
- package/src/components/context-pane.js +9 -9
- package/src/components/files-modals.js +3 -3
- package/src/components/files.js +21 -5
- package/src/components/freddie.js +25 -25
- package/src/components/sessions.js +37 -23
- package/src/components/shell.js +67 -5
- package/src/components/theme-toggle.js +12 -5
package/app-shell.css
CHANGED
|
@@ -143,8 +143,8 @@ pre {
|
|
|
143
143
|
margin: 0;
|
|
144
144
|
border-radius: var(--r-3);
|
|
145
145
|
}
|
|
146
|
-
pre .k { color: var(--mascot); }
|
|
147
|
-
pre .s { color: var(--
|
|
146
|
+
pre .k { color: var(--code-str-alt, var(--mascot)); }
|
|
147
|
+
pre .s { color: var(--code-string, var(--green)); }
|
|
148
148
|
pre .c { color: var(--fg-3); }
|
|
149
149
|
pre .n { color: var(--green-2); }
|
|
150
150
|
|
|
@@ -190,7 +190,7 @@ pre .n { color: var(--green-2); }
|
|
|
190
190
|
body.canvas-host { background: transparent !important; }
|
|
191
191
|
|
|
192
192
|
:root {
|
|
193
|
-
--app-status-h:
|
|
193
|
+
--app-status-h: 26px;
|
|
194
194
|
--app-topbar-h: var(--size-lg);
|
|
195
195
|
--app-crumb-h: var(--size-sm);
|
|
196
196
|
}
|
|
@@ -384,27 +384,37 @@ body.canvas-host { background: transparent !important; }
|
|
|
384
384
|
.app-status {
|
|
385
385
|
display: flex; align-items: center; gap: var(--space-3);
|
|
386
386
|
width: 100%;
|
|
387
|
-
min-height: var(--app-status-h);
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
height: var(--app-status-h); min-height: var(--app-status-h);
|
|
388
|
+
/* A thin desktop status strip, not a webpage footer band. */
|
|
389
|
+
padding: 0 var(--space-4);
|
|
390
|
+
/* Status chrome is prose, not code - mono is reserved for code/paths. */
|
|
391
|
+
font-family: var(--ff-body); font-size: var(--fs-xs); line-height: 1.2;
|
|
390
392
|
color: var(--fg-3);
|
|
391
393
|
border-top: 1px solid var(--rule);
|
|
392
394
|
}
|
|
393
|
-
.app-status .item { color: inherit; }
|
|
395
|
+
.app-status .item { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
|
|
394
396
|
.app-status .item:first-of-type { color: var(--accent); }
|
|
395
397
|
.app-status .spread { flex: 1; }
|
|
398
|
+
/* The status bar NEVER wraps: at narrow widths the trailing items (hints,
|
|
399
|
+
agent target) drop in priority order instead of breaking mid-word onto a
|
|
400
|
+
second line. */
|
|
401
|
+
.app-status { flex-wrap: nowrap; overflow: hidden; }
|
|
402
|
+
@media (max-width: 1100px) {
|
|
403
|
+
.app-status .item:last-of-type:not(:only-of-type) { display: none; }
|
|
404
|
+
}
|
|
396
405
|
|
|
397
406
|
/* ============================================================
|
|
398
407
|
Primitives
|
|
399
408
|
============================================================ */
|
|
400
409
|
.btn, .btn-primary, .btn-ghost {
|
|
401
|
-
display: inline-flex; align-items: center; gap:
|
|
402
|
-
padding:
|
|
410
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
411
|
+
padding: 8px 14px; min-height: 32px;
|
|
403
412
|
font-family: var(--ff-body);
|
|
404
413
|
font-weight: 600; font-size: var(--fs-sm);
|
|
405
414
|
text-decoration: none;
|
|
406
415
|
cursor: pointer;
|
|
407
|
-
|
|
416
|
+
/* Rounded-rect app chrome, not a marketing-page stadium CTA. */
|
|
417
|
+
border-radius: var(--r-1);
|
|
408
418
|
border: 0;
|
|
409
419
|
transition: transform var(--dur-snap) var(--ease), background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
410
420
|
}
|
|
@@ -439,7 +449,8 @@ body.canvas-host { background: transparent !important; }
|
|
|
439
449
|
.ds-icon-btn-ghost:hover { background: var(--bg-2); }
|
|
440
450
|
.ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
|
|
441
451
|
.ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
|
|
442
|
-
|
|
452
|
+
/* warn = destructive ACTION tone; flame stays exclusively error STATUS. */
|
|
453
|
+
.ds-icon-btn-danger { background: var(--warn); color: var(--paper); }
|
|
443
454
|
.ds-icon-btn-danger:hover { filter: brightness(1.1); }
|
|
444
455
|
.ds-icon-btn:active { transform: translateY(1px); }
|
|
445
456
|
.ds-icon-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
@@ -513,11 +524,15 @@ body.canvas-host { background: transparent !important; }
|
|
|
513
524
|
.panel.panel-wide { background: transparent; }
|
|
514
525
|
.panel-head {
|
|
515
526
|
display: flex; align-items: baseline; justify-content: space-between;
|
|
516
|
-
|
|
527
|
+
/* Shares the .panel-body 16px side padding so the caps label and the body
|
|
528
|
+
rows sit on ONE left axis (the old 24/32 padding was authored for the
|
|
529
|
+
pre-padding .panel-wide era and indented the label 16px past its content). */
|
|
530
|
+
padding: var(--space-2) var(--space-3);
|
|
517
531
|
font-size: var(--fs-xs); font-weight: 600;
|
|
518
532
|
color: var(--fg-3);
|
|
519
533
|
letter-spacing: var(--tr-caps); text-transform: uppercase;
|
|
520
534
|
}
|
|
535
|
+
.panel.panel-wide .panel-head { padding-left: 0; padding-right: 0; }
|
|
521
536
|
.panel-head > :last-child {
|
|
522
537
|
font-weight: 500; color: var(--fg-3);
|
|
523
538
|
font-family: var(--ff-mono); letter-spacing: 0;
|
|
@@ -585,6 +600,12 @@ body.canvas-host { background: transparent !important; }
|
|
|
585
600
|
.row .code { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
|
|
586
601
|
.row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug, 1.3); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
|
|
587
602
|
.row .title .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
|
|
603
|
+
/* App typescale: list rows are quiet working chrome (the 18px/600 default is a
|
|
604
|
+
marketing-surface voice). One size for ALL app list rows - matches
|
|
605
|
+
.ds-file-row/.ds-session-title at fs-sm/500; values mirror the kit's own
|
|
606
|
+
mobile block below. Marketing pages without data-typescale keep the default. */
|
|
607
|
+
[data-typescale="app"] .row { padding: 12px 16px; }
|
|
608
|
+
[data-typescale="app"] .row .title { font-size: var(--fs-sm); font-weight: 500; }
|
|
588
609
|
.row .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
|
|
589
610
|
.row .meta { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; align-self: center; }
|
|
590
611
|
/* WorksList meta pairs a label with a disclosure chevron, inline-aligned. */
|
|
@@ -1030,8 +1051,8 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1030
1051
|
padding: 12px 18px; font-size: var(--fs-sm);
|
|
1031
1052
|
}
|
|
1032
1053
|
|
|
1033
|
-
/* Panel */
|
|
1034
|
-
.panel-head { padding: var(--space-
|
|
1054
|
+
/* Panel - keep the head on the body's left axis at laptop widths too. */
|
|
1055
|
+
.panel-head { padding: var(--space-2) var(--space-3); }
|
|
1035
1056
|
.panel-body { padding: var(--space-2) var(--space-3); }
|
|
1036
1057
|
|
|
1037
1058
|
/* Hero — fluid base font-size; only width unconstrained on tablet. */
|
|
@@ -1103,13 +1124,15 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1103
1124
|
|
|
1104
1125
|
/* Listing wrapper holds the optional filter + sort header above the grid. */
|
|
1105
1126
|
.ds-file-listing { display: flex; flex-direction: column; gap: var(--space-2); min-height: 0; }
|
|
1106
|
-
|
|
1127
|
+
/* The quick filter is a compact control, not a full-width form row - a giant
|
|
1128
|
+
input above the grid reads as a search page and costs fold height. */
|
|
1129
|
+
.ds-file-filter { padding: 0 0 var(--space-1); display: flex; justify-content: flex-end; }
|
|
1107
1130
|
.ds-file-filter-input {
|
|
1108
|
-
width: 100
|
|
1131
|
+
width: min(280px, 100%); padding: 6px 12px; font-size: var(--fs-sm);
|
|
1109
1132
|
background: var(--bg); color: var(--fg);
|
|
1110
|
-
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-
|
|
1133
|
+
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
|
|
1111
1134
|
}
|
|
1112
|
-
.ds-file-filter-input:focus-visible { outline: 2px
|
|
1135
|
+
.ds-file-filter-input:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
|
|
1113
1136
|
.ds-file-sort { display: flex; gap: var(--space-2); padding: 0 var(--space-2) var(--space-1); }
|
|
1114
1137
|
.ds-file-sort-btn {
|
|
1115
1138
|
font-size: var(--fs-tiny); font-family: var(--ff-mono); color: var(--fg-3);
|
|
@@ -1121,6 +1144,16 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1121
1144
|
|
|
1122
1145
|
/* Skeleton shimmer rows shown while a directory loads. */
|
|
1123
1146
|
.ds-file-row-skeleton { cursor: default; pointer-events: none; }
|
|
1147
|
+
/* In-place refresh: dim the populated grid instead of swapping it for shimmer
|
|
1148
|
+
rows (the rows stay; the round-trip reads as a settle, not a reload). */
|
|
1149
|
+
.ds-file-grid.is-refreshing { opacity: .6; }
|
|
1150
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1151
|
+
.ds-file-grid { transition: opacity .15s var(--ease); }
|
|
1152
|
+
}
|
|
1153
|
+
/* EventList loading skeleton (shares the .ds-skel shimmer base above). */
|
|
1154
|
+
.ds-event-row-skeleton { display: flex; align-items: center; gap: var(--space-3); padding: 12px 16px; pointer-events: none; }
|
|
1155
|
+
.ds-skel-rank { height: 12px; width: 2.5ch; }
|
|
1156
|
+
.ds-event-state { padding: var(--space-2) 16px; }
|
|
1124
1157
|
.ds-skel { display: inline-block; border-radius: var(--r-1); background: var(--bg-2); position: relative; overflow: hidden; }
|
|
1125
1158
|
.ds-skel::after {
|
|
1126
1159
|
content: ''; position: absolute; inset: 0;
|
|
@@ -1169,7 +1202,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1169
1202
|
.ds-file-row[data-file-type="code"] { border-left-width: 3px; border-left-color: var(--green-2); }
|
|
1170
1203
|
.ds-file-row[data-file-type="text"] { border-left-width: 3px; border-left-color: var(--ink-3); }
|
|
1171
1204
|
.ds-file-row[data-file-type="archive"] { border-left-width: 3px; border-left-color: var(--flame); }
|
|
1172
|
-
.ds-file-row[data-file-type="document"] { border-left-width: 3px; border-left-color: var(--sun); }
|
|
1205
|
+
.ds-file-row[data-file-type="document"] { border-left-width: 3px; border-left-color: var(--amber, var(--sun)); }
|
|
1173
1206
|
.ds-file-row[data-file-type="symlink"] { border-left-width: 3px; border-left-color: var(--purple); }
|
|
1174
1207
|
.ds-file-row[data-file-type="other"] { border-left-width: 3px; border-left-color: var(--fg-3); }
|
|
1175
1208
|
|
|
@@ -1200,7 +1233,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1200
1233
|
.ds-file-row[data-file-type="audio"] .ds-file-icon { color: var(--sky); }
|
|
1201
1234
|
.ds-file-row[data-file-type="code"] .ds-file-icon { color: var(--green-2); }
|
|
1202
1235
|
.ds-file-row[data-file-type="archive"] .ds-file-icon { color: var(--flame); }
|
|
1203
|
-
.ds-file-row[data-file-type="document"] .ds-file-icon { color: var(--sun); }
|
|
1236
|
+
.ds-file-row[data-file-type="document"] .ds-file-icon { color: var(--amber, var(--sun)); }
|
|
1204
1237
|
|
|
1205
1238
|
/* Row actions — hidden until hover/focus, revealed without layout shift. */
|
|
1206
1239
|
.ds-file-actions {
|
|
@@ -1250,6 +1283,19 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1250
1283
|
background: var(--bg-2); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
1251
1284
|
}
|
|
1252
1285
|
.ds-bulkbar-count { font-size: var(--fs-tiny); color: var(--fg-2); }
|
|
1286
|
+
/* BulkBar is a toolbar (it even declares role=toolbar): compact rect buttons,
|
|
1287
|
+
quiet destructive outline - the app arm-confirms destructive bulk actions
|
|
1288
|
+
via ConfirmDialog, so the strip never needs a loud CTA. */
|
|
1289
|
+
.ds-bulkbar .btn, .ds-bulkbar .btn-primary {
|
|
1290
|
+
padding: 5px 12px; min-height: 32px; border-radius: var(--r-1); font-weight: 500;
|
|
1291
|
+
}
|
|
1292
|
+
.ds-bulkbar .btn { background: transparent; border: var(--bw-hair) solid var(--rule); color: var(--fg-2); }
|
|
1293
|
+
.ds-bulkbar .btn:hover { background: var(--bg-2); color: var(--fg); }
|
|
1294
|
+
.ds-bulkbar .btn-primary.danger { background: transparent; color: var(--warn); border: var(--bw-hair) solid var(--warn); }
|
|
1295
|
+
.ds-bulkbar .btn-primary.danger:hover { background: color-mix(in oklab, var(--warn) 12%, transparent); color: var(--warn); }
|
|
1296
|
+
@media (pointer: coarse) {
|
|
1297
|
+
.ds-bulkbar .btn, .ds-bulkbar .btn-primary { min-height: 44px; }
|
|
1298
|
+
}
|
|
1253
1299
|
|
|
1254
1300
|
/* Density picker — list / compact / thumbnails. */
|
|
1255
1301
|
.ds-density {
|
|
@@ -1336,6 +1382,11 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1336
1382
|
.app-main > div > .ds-file-stage,
|
|
1337
1383
|
.app-main .ds-file-stage { padding-top: 0; }
|
|
1338
1384
|
|
|
1385
|
+
/* Full-width files stack: the stage's space-3 vertical beat without its
|
|
1386
|
+
920px cap/auto-margins, so the roots / toolbar / bulkbar / uploads / grid
|
|
1387
|
+
bands keep one consistent rhythm instead of touching edge-to-edge. */
|
|
1388
|
+
.ds-files-stack { display: flex; flex-direction: column; gap: var(--space-3); min-height: 0; }
|
|
1389
|
+
|
|
1339
1390
|
/* Breadcrumb path */
|
|
1340
1391
|
.ds-crumb-path {
|
|
1341
1392
|
display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
|
|
@@ -1356,10 +1407,38 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1356
1407
|
display: flex; align-items: center; justify-content: space-between;
|
|
1357
1408
|
gap: var(--space-2); flex-wrap: wrap;
|
|
1358
1409
|
}
|
|
1410
|
+
/* Dense page header: one row, small heading, single-line muted lede. The
|
|
1411
|
+
working surfaces (files, live, history, settings) lead with content, not a
|
|
1412
|
+
display H1 + paragraph that costs the first 150px of every fold. */
|
|
1413
|
+
.ds-page-header-dense { margin: 0 0 var(--space-3); }
|
|
1414
|
+
.ds-page-header-dense-row { display: flex; align-items: baseline; gap: var(--space-3); min-width: 0; }
|
|
1415
|
+
.ds-page-header-dense-row h1 {
|
|
1416
|
+
margin: 0; font-size: var(--fs-lg); line-height: 1.3; font-weight: 600;
|
|
1417
|
+
letter-spacing: normal; flex: 0 0 auto;
|
|
1418
|
+
}
|
|
1419
|
+
.ds-page-header-dense-lede {
|
|
1420
|
+
flex: 1 1 auto; min-width: 0;
|
|
1421
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
1422
|
+
font-size: var(--fs-sm); color: var(--fg-3);
|
|
1423
|
+
}
|
|
1424
|
+
.ds-page-header-dense .ds-page-header-right { flex: 0 0 auto; margin-left: auto; }
|
|
1359
1425
|
.ds-file-toolbar-left,
|
|
1360
1426
|
.ds-file-toolbar-right {
|
|
1361
1427
|
display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
|
|
1362
1428
|
}
|
|
1429
|
+
/* Toolbar-scoped buttons: quiet, compact, rectangular - a toolbar is chrome,
|
|
1430
|
+
not a CTA row; the stadium pill stays for real page-level actions. */
|
|
1431
|
+
.ds-file-toolbar .btn, .ds-file-toolbar .btn-ghost {
|
|
1432
|
+
padding: 5px 12px; min-height: 32px;
|
|
1433
|
+
border-radius: var(--r-1);
|
|
1434
|
+
font-weight: 500;
|
|
1435
|
+
background: transparent;
|
|
1436
|
+
border: var(--bw-hair) solid var(--rule); color: var(--fg-2);
|
|
1437
|
+
}
|
|
1438
|
+
.ds-file-toolbar .btn:hover, .ds-file-toolbar .btn-ghost:hover { background: var(--bg-2); color: var(--fg); }
|
|
1439
|
+
@media (pointer: coarse) {
|
|
1440
|
+
.ds-file-toolbar .btn, .ds-file-toolbar .btn-ghost { min-height: 44px; }
|
|
1441
|
+
}
|
|
1363
1442
|
.ds-meta-mono {
|
|
1364
1443
|
font-family: var(--ff-mono); font-size: var(--fs-xs);
|
|
1365
1444
|
color: var(--fg-3); letter-spacing: var(--tr-caps);
|
|
@@ -1400,6 +1479,20 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1400
1479
|
0%, 100% { border-color: var(--accent); }
|
|
1401
1480
|
50% { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
|
|
1402
1481
|
}
|
|
1482
|
+
/* Wrapper form (has children): no permanent chrome - the content renders as if
|
|
1483
|
+
the zone were not there, and the dashed affordance overlays it ONLY while a
|
|
1484
|
+
drag is in flight. */
|
|
1485
|
+
.ds-dropzone--wrap { position: relative; border: none; border-radius: 0; background: transparent; }
|
|
1486
|
+
.ds-dropzone--wrap > .ds-dropzone-inner { display: none; }
|
|
1487
|
+
.ds-dropzone--wrap.dragover > .ds-dropzone-inner {
|
|
1488
|
+
display: flex; position: absolute; inset: 0; z-index: 5;
|
|
1489
|
+
margin: 0; padding: var(--space-3);
|
|
1490
|
+
align-items: center; justify-content: center;
|
|
1491
|
+
background: color-mix(in srgb, var(--bg) 84%, transparent);
|
|
1492
|
+
outline: var(--bw-rule) dashed var(--accent); outline-offset: -6px;
|
|
1493
|
+
border-radius: var(--r-3);
|
|
1494
|
+
}
|
|
1495
|
+
.ds-dropzone--wrap.dragover { animation: none; }
|
|
1403
1496
|
|
|
1404
1497
|
/* Upload progress */
|
|
1405
1498
|
.ds-upload-progress { display: flex; flex-direction: column; gap: 6px; }
|
|
@@ -1593,7 +1686,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1593
1686
|
border-radius: var(--r-pill); color: var(--fg);
|
|
1594
1687
|
font-family: inherit; font-size: var(--fs-xs);
|
|
1595
1688
|
}
|
|
1596
|
-
.ds-filter-input:focus { outline: 2px
|
|
1689
|
+
.ds-filter-input:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
|
|
1597
1690
|
|
|
1598
1691
|
/* Loading skeleton — placeholder rows while a directory loads. */
|
|
1599
1692
|
.ds-file-grid-loading { display: flex; flex-direction: column; gap: 4px; }
|
|
@@ -1620,44 +1713,19 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1620
1713
|
.ds-file-row[draggable="true"] { cursor: grab; }
|
|
1621
1714
|
.ds-file-row[draggable="true"]:active { cursor: grabbing; }
|
|
1622
1715
|
|
|
1623
|
-
/*
|
|
1716
|
+
/* (A stale duplicate multi-select block used to live here: an absolute-overlay
|
|
1717
|
+
.ds-file-check hidden until hover, plus .ds-file-check.on / .ds-file-row.selected
|
|
1718
|
+
/ .ds-bulk-bar rules NO component ever emits. Being later in source at equal
|
|
1719
|
+
specificity it clobbered the real in-flow checkbox at ~1243 - the shipped
|
|
1720
|
+
multi-select rendered invisible-until-hover with clipped brackets. The live
|
|
1721
|
+
rules are the earlier block; only the still-load-bearing bits remain below.) */
|
|
1624
1722
|
.ds-file-row { position: relative; }
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
1629
|
-
border: var(--bw-hair) solid var(--rule); border-radius: 5px;
|
|
1630
|
-
background: var(--bg); color: var(--accent-fg);
|
|
1631
|
-
font-size: var(--fs-micro); line-height: 1; cursor: pointer;
|
|
1632
|
-
opacity: 0; transition: opacity var(--dur-base) var(--ease), background var(--dur-snap) var(--ease);
|
|
1633
|
-
}
|
|
1634
|
-
.ds-file-row:hover .ds-file-check,
|
|
1635
|
-
.ds-file-row:focus-within .ds-file-check,
|
|
1636
|
-
.ds-file-check.on { opacity: 1; }
|
|
1637
|
-
/* Touch / coarse-pointer devices have no hover — keep checkboxes AND the
|
|
1638
|
-
per-row action buttons (rename/delete/download) visible so the file manager
|
|
1639
|
-
is fully reachable without a pointer (e.g. an iPad in landscape). */
|
|
1723
|
+
/* Touch / coarse-pointer devices have no hover — keep the per-row action
|
|
1724
|
+
buttons (rename/delete/download) visible so the file manager is fully
|
|
1725
|
+
reachable without a pointer (e.g. an iPad in landscape). */
|
|
1640
1726
|
@media (hover: none), (pointer: coarse) {
|
|
1641
|
-
.ds-file-check { opacity: 1; }
|
|
1642
1727
|
.ds-file-actions { opacity: 1; }
|
|
1643
1728
|
}
|
|
1644
|
-
.ds-file-check.on { background: var(--accent); border-color: var(--accent); }
|
|
1645
|
-
.ds-file-row.selected {
|
|
1646
|
-
background: var(--accent-tint);
|
|
1647
|
-
border-color: var(--accent);
|
|
1648
|
-
}
|
|
1649
|
-
.ds-file-row.selected:hover { background: color-mix(in oklab, var(--accent) 22%, var(--bg)); }
|
|
1650
|
-
|
|
1651
|
-
.ds-bulk-bar {
|
|
1652
|
-
display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2);
|
|
1653
|
-
padding: 10px 14px; border-radius: var(--r-2);
|
|
1654
|
-
background: var(--accent-tint);
|
|
1655
|
-
border: var(--bw-hair) solid var(--accent);
|
|
1656
|
-
position: sticky; top: var(--space-2); z-index: 2;
|
|
1657
|
-
}
|
|
1658
|
-
.ds-bulk-count {
|
|
1659
|
-
font-weight: 600; font-size: var(--fs-sm); margin-right: auto;
|
|
1660
|
-
}
|
|
1661
1729
|
|
|
1662
1730
|
/* Keyboard-shortcuts hint — compact two-column legend. */
|
|
1663
1731
|
.ds-shortcuts-hint {
|
|
@@ -1700,6 +1768,13 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1700
1768
|
font-family: var(--ff-mono); font-size: var(--fs-xs);
|
|
1701
1769
|
display: inline-flex; align-items: center; gap: 6px;
|
|
1702
1770
|
}
|
|
1771
|
+
/* CSS-drawn half-disc mark on the compact theme toggle: keeps the control
|
|
1772
|
+
legible when its text label is hidden (icon-only rail strip). */
|
|
1773
|
+
.ds-theme-disc {
|
|
1774
|
+
flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%;
|
|
1775
|
+
border: var(--bw-hair) solid var(--fg-3);
|
|
1776
|
+
background: linear-gradient(90deg, var(--fg-3) 0 50%, transparent 50% 100%);
|
|
1777
|
+
}
|
|
1703
1778
|
|
|
1704
1779
|
/* ============================================================
|
|
1705
1780
|
Chat kit polish — styles every class emitted by Chat /
|
|
@@ -1880,10 +1955,10 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
1880
1955
|
.chat-bubble.chat-code .token.atrule,
|
|
1881
1956
|
.chat-bubble.chat-code .token.selector { color: var(--accent); }
|
|
1882
1957
|
.chat-bubble.chat-code .token.string,
|
|
1883
|
-
.chat-bubble.chat-code .token.attr-value { color: var(--mascot); }
|
|
1958
|
+
.chat-bubble.chat-code .token.attr-value { color: var(--code-str-alt, var(--mascot)); }
|
|
1884
1959
|
.chat-bubble.chat-code .token.comment { color: var(--fg-3); font-style: italic; }
|
|
1885
1960
|
.chat-bubble.chat-code .token.number,
|
|
1886
|
-
.chat-bubble.chat-code .token.boolean { color: var(--sun); }
|
|
1961
|
+
.chat-bubble.chat-code .token.boolean { color: var(--code-num, var(--sun)); }
|
|
1887
1962
|
.chat-bubble.chat-code .token.punctuation { color: var(--fg-2); }
|
|
1888
1963
|
.chat-bubble.chat-code .token.property,
|
|
1889
1964
|
.chat-bubble.chat-code .token.attr-name { color: var(--sky); }
|
|
@@ -2052,7 +2127,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
2052
2127
|
display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--space-2);
|
|
2053
2128
|
padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
|
|
2054
2129
|
background: var(--bg);
|
|
2055
|
-
|
|
2130
|
+
/* The composer sits bg-on-bg: the 14% --rule hairline is ~1.3:1 on paper,
|
|
2131
|
+
leaving the primary input near-invisible at rest - use the strong rule. */
|
|
2132
|
+
border: var(--bw-hair) solid var(--rule-strong);
|
|
2056
2133
|
border-radius: var(--r-2);
|
|
2057
2134
|
flex-shrink: 0;
|
|
2058
2135
|
transition: border-color var(--dur-snap) var(--ease), box-shadow var(--dur-snap) var(--ease);
|
|
@@ -2066,7 +2143,9 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
2066
2143
|
background: none; color: var(--fg);
|
|
2067
2144
|
border: none; border-radius: 0;
|
|
2068
2145
|
font-family: inherit; font-size: var(--fs-sm);
|
|
2069
|
-
|
|
2146
|
+
/* 1.5 is the value that actually renders (a later polish block used to
|
|
2147
|
+
re-declare it; the sizing block now states the truth). */
|
|
2148
|
+
line-height: 1.5; resize: none;
|
|
2070
2149
|
min-height: 28px; max-height: 200px;
|
|
2071
2150
|
box-sizing: border-box; overflow-y: auto;
|
|
2072
2151
|
scrollbar-width: thin;
|
|
@@ -2133,13 +2212,19 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
2133
2212
|
/* ── select primitive ─────────────────────────────────────────────────── */
|
|
2134
2213
|
.ds-select {
|
|
2135
2214
|
width: 100%;
|
|
2136
|
-
|
|
2215
|
+
min-width: 0;
|
|
2216
|
+
padding: 10px 30px 10px 14px; /* right gap clears the chevron */
|
|
2137
2217
|
background: var(--bg-2);
|
|
2138
2218
|
border: 0;
|
|
2139
2219
|
border-radius: var(--r-2);
|
|
2140
2220
|
font-family: inherit;
|
|
2141
2221
|
font-size: var(--fs-sm);
|
|
2142
2222
|
color: var(--fg);
|
|
2223
|
+
/* Clip long option text gracefully - a select that cuts 'Claude Sonnet
|
|
2224
|
+
(latest' mid-parenthesis reads as broken; ellipsis reads as truncated. */
|
|
2225
|
+
text-overflow: ellipsis;
|
|
2226
|
+
white-space: nowrap;
|
|
2227
|
+
overflow: hidden;
|
|
2143
2228
|
appearance: none;
|
|
2144
2229
|
background-image: linear-gradient(45deg, transparent 50%, var(--fg-3) 50%),
|
|
2145
2230
|
linear-gradient(135deg, var(--fg-3) 50%, transparent 50%);
|
|
@@ -2148,15 +2233,12 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
2148
2233
|
background-repeat: no-repeat;
|
|
2149
2234
|
cursor: pointer;
|
|
2150
2235
|
}
|
|
2151
|
-
.ds-select:focus { box-shadow: inset 0 0 0 2px var(--accent); }
|
|
2236
|
+
.ds-select:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
|
|
2152
2237
|
.ds-select:hover { background-color: var(--bg-3); }
|
|
2153
2238
|
|
|
2154
|
-
/* ── chat composer autogrow polish
|
|
2239
|
+
/* ── chat composer autogrow polish (sizing lives in the primary block) ── */
|
|
2155
2240
|
.chat-composer textarea {
|
|
2156
|
-
resize: none;
|
|
2157
|
-
overflow-y: auto;
|
|
2158
2241
|
transition: height var(--dur-snap) var(--ease);
|
|
2159
|
-
line-height: 1.5;
|
|
2160
2242
|
}
|
|
2161
2243
|
.chat-composer textarea:disabled {
|
|
2162
2244
|
opacity: 0.5;
|
|
@@ -2927,10 +3009,13 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
|
|
|
2927
3009
|
All sizing/colour from kit tokens; no hardcoded palette.
|
|
2928
3010
|
---------------------------------------------------------------------------- */
|
|
2929
3011
|
.ws-shell {
|
|
2930
|
-
|
|
3012
|
+
/* Fluid chrome columns: shrink on small laptops, breathe on ultrawide, so the
|
|
3013
|
+
~848px of fixed chrome no longer eats a constant slab. An inline --ws-*-w
|
|
3014
|
+
written by a resize drag overrides these (inline wins), pinning the width. */
|
|
3015
|
+
--ws-rail-w: clamp(200px, 16vw, 260px);
|
|
2931
3016
|
--ws-rail-w-collapsed: 60px;
|
|
2932
|
-
--ws-sessions-w:
|
|
2933
|
-
--ws-pane-w:
|
|
3017
|
+
--ws-sessions-w: clamp(248px, 22vw, 360px);
|
|
3018
|
+
--ws-pane-w: clamp(288px, 24vw, 420px);
|
|
2934
3019
|
display: grid;
|
|
2935
3020
|
grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) 1fr var(--ws-pane-w);
|
|
2936
3021
|
grid-template-areas: "rail sessions content pane";
|
|
@@ -2951,6 +3036,21 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
|
|
|
2951
3036
|
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions { grid-template-columns: var(--ws-rail-w) 1fr var(--ws-pane-w); grid-template-areas: "rail content pane"; }
|
|
2952
3037
|
.ws-shell.ws-rail-collapsed { --ws-rail-w: var(--ws-rail-w-collapsed); }
|
|
2953
3038
|
.ws-shell.ws-pane-collapsed { --ws-pane-w: 0px; }
|
|
3039
|
+
/* Sessions column desktop collapse (parity with the pane collapse), reclaiming
|
|
3040
|
+
its width for a full-width thread/grid. */
|
|
3041
|
+
.ws-shell.ws-sessions-collapsed { --ws-sessions-w: 0px; }
|
|
3042
|
+
.ws-sessions-collapsed .ws-sessions { overflow: hidden; border-right: none; }
|
|
3043
|
+
.ws-sessions-collapsed .ws-sessions > * { display: none; }
|
|
3044
|
+
/* Column resize handles: a thin keyboard-accessible separator pinned to the
|
|
3045
|
+
right edge of each chrome track; drag (or ArrowLeft/Right) writes a clamped
|
|
3046
|
+
inline --ws-*-w. */
|
|
3047
|
+
.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; }
|
|
3048
|
+
.ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background: transparent; transition: background var(--dur-snap) var(--ease); }
|
|
3049
|
+
.ws-resizer:hover::after, .ws-resizer:focus-visible::after { background: var(--accent); }
|
|
3050
|
+
.ws-resizer:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
3051
|
+
.ws-resizer.ws-resizer-rail { grid-column: 1; }
|
|
3052
|
+
.ws-resizer.ws-resizer-sessions { grid-column: 2; }
|
|
3053
|
+
.ws-resizer.ws-resizer-pane { grid-column: 3; justify-self: end; }
|
|
2954
3054
|
/* Ease the rail/pane collapse. Track COUNT stays stable on collapse (only a
|
|
2955
3055
|
width var flips), so grid-template-columns is animatable; reduced-motion
|
|
2956
3056
|
drops it to an instant swap. */
|
|
@@ -3059,36 +3159,114 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
|
|
|
3059
3159
|
.ws-pane-toggle:hover { background: var(--bg-3); color: var(--fg); }
|
|
3060
3160
|
.ws-pane-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
3061
3161
|
|
|
3062
|
-
/*
|
|
3063
|
-
|
|
3064
|
-
|
|
3162
|
+
/* Drawer toggles and the scrim are hidden by default and revealed by the staged
|
|
3163
|
+
media blocks BELOW - these base rules must precede those blocks in source
|
|
3164
|
+
order: at equal specificity the later rule wins regardless of media, so a
|
|
3165
|
+
trailing display:none silently kills every drawer affordance (shipped bug:
|
|
3166
|
+
the mobile drawers were dead because these lines used to sit last). */
|
|
3167
|
+
.ws-drawer-toggle { display: none; align-items: center; justify-content: center; width: 40px; height: 40px; border: none; background: none; color: var(--fg-2); cursor: pointer; border-radius: var(--r-1); }
|
|
3168
|
+
/* Desktop-only chrome toggle (sessions collapse): inverse of the mobile drawer-toggle. */
|
|
3169
|
+
.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); }
|
|
3170
|
+
.ws-desktop-toggle:hover { background: var(--bg-2); color: var(--fg); }
|
|
3171
|
+
.ws-desktop-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
3172
|
+
@media (max-width: 900px) { .ws-desktop-toggle { display: none; } }
|
|
3173
|
+
.ws-scrim { display: none; }
|
|
3174
|
+
|
|
3175
|
+
/* Responsive: the columns yield to the CONTENT in stages - the main column is
|
|
3176
|
+
the product, so the right pane gives way first, the sessions list second,
|
|
3177
|
+
and only below 900px does the rail itself drop to a fixed icon strip. Yielded
|
|
3178
|
+
columns stay reachable as overlay drawers (.ws-pane-open / .ws-sessions-open,
|
|
3179
|
+
toggled from the crumb bar) over a shared fade scrim. Before this staging the
|
|
3180
|
+
4-track grid survived down to 901px and crushed the chat thread to ~245px
|
|
3181
|
+
while the 320px context pane kept its full width. */
|
|
3182
|
+
|
|
3183
|
+
/* Stage 1 (<=1480px): drop the pane TRACK; the context pane becomes a right
|
|
3184
|
+
overlay drawer. */
|
|
3185
|
+
@media (max-width: 1480px) {
|
|
3186
|
+
.ws-shell,
|
|
3187
|
+
.ws-shell.ws-no-pane,
|
|
3188
|
+
.ws-shell.ws-pane-collapsed,
|
|
3189
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions) {
|
|
3190
|
+
grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) minmax(0, 1fr);
|
|
3191
|
+
grid-template-areas: "rail sessions content";
|
|
3192
|
+
}
|
|
3193
|
+
.ws-shell.ws-no-sessions,
|
|
3194
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
3195
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
3196
|
+
grid-template-columns: var(--ws-rail-w) minmax(0, 1fr);
|
|
3197
|
+
grid-template-areas: "rail content";
|
|
3198
|
+
}
|
|
3199
|
+
/* Drawer width is a literal: --ws-pane-w is 0px while pane-collapsed, and a
|
|
3200
|
+
desktop-collapsed pane must still open as a full drawer. */
|
|
3201
|
+
.ws-pane {
|
|
3202
|
+
position: fixed; inset: 0 0 0 auto;
|
|
3203
|
+
width: min(340px, 85vw);
|
|
3204
|
+
z-index: 42; transform: translateX(110%);
|
|
3205
|
+
transition: transform var(--dur-base) var(--ease);
|
|
3206
|
+
}
|
|
3207
|
+
.ws-shell.ws-pane-open .ws-pane { transform: translateX(0); width: min(340px, 85vw); }
|
|
3208
|
+
.ws-shell.ws-pane-open.ws-pane-collapsed .ws-pane { border-left: var(--bw-hair) solid var(--bg-3); }
|
|
3209
|
+
.ws-shell.ws-pane-open.ws-pane-collapsed .ws-pane > :not(.ws-pane-toggle) { display: revert; }
|
|
3210
|
+
/* The desktop collapse chevron is meaningless in drawer mode. */
|
|
3211
|
+
.ws-pane-toggle { display: none; }
|
|
3212
|
+
.ws-pane-drawer-toggle { display: inline-flex; }
|
|
3213
|
+
/* Scrim is always present from this stage down so it FADES with the drawer
|
|
3214
|
+
instead of hard-appearing; pointer-events gate keeps it inert while closed. */
|
|
3215
|
+
.ws-scrim { display: block; opacity: 0; pointer-events: none; position: fixed; inset: 0; z-index: 41; background: color-mix(in srgb, var(--fg) 38%, transparent); transition: opacity var(--dur-base) var(--ease); }
|
|
3216
|
+
.ws-shell.ws-sessions-open .ws-scrim, .ws-shell.ws-pane-open .ws-scrim { opacity: 1; pointer-events: auto; }
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
/* Stage 2 (<=1100px): drop the sessions TRACK; the conversation list becomes a
|
|
3220
|
+
left overlay drawer. */
|
|
3221
|
+
@media (max-width: 1100px) {
|
|
3222
|
+
.ws-shell,
|
|
3223
|
+
.ws-shell.ws-no-pane,
|
|
3224
|
+
.ws-shell.ws-pane-collapsed,
|
|
3225
|
+
.ws-shell.ws-no-sessions,
|
|
3226
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
3227
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions),
|
|
3228
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
3229
|
+
grid-template-columns: var(--ws-rail-w) minmax(0, 1fr);
|
|
3230
|
+
grid-template-areas: "rail content";
|
|
3231
|
+
}
|
|
3232
|
+
.ws-sessions {
|
|
3233
|
+
position: fixed; inset: 0 auto 0 0;
|
|
3234
|
+
width: min(var(--ws-sessions-w), 80vw);
|
|
3235
|
+
z-index: 42; transform: translateX(-110%);
|
|
3236
|
+
transition: transform var(--dur-base) var(--ease);
|
|
3237
|
+
border-right: var(--bw-hair) solid var(--bg-3);
|
|
3238
|
+
}
|
|
3239
|
+
.ws-shell.ws-sessions-open .ws-sessions { transform: translateX(0); }
|
|
3240
|
+
.ws-sessions-drawer-toggle { display: inline-flex; }
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
/* Stage 3 (<=900px): single content column; the rail drops to a fixed icon-only
|
|
3244
|
+
strip. Labels hide UNCONDITIONALLY here - a 60px rail showing clipped label
|
|
3245
|
+
text ('age', 'Ne') is the worst of both worlds. */
|
|
3065
3246
|
@media (max-width: 900px) {
|
|
3066
3247
|
.ws-shell,
|
|
3067
3248
|
.ws-shell.ws-no-sessions,
|
|
3068
3249
|
.ws-shell.ws-no-pane,
|
|
3069
|
-
.ws-shell.ws-
|
|
3070
|
-
|
|
3250
|
+
.ws-shell.ws-pane-collapsed,
|
|
3251
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
3252
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions),
|
|
3253
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
3254
|
+
grid-template-columns: minmax(0, 1fr);
|
|
3071
3255
|
grid-template-areas: "content";
|
|
3072
3256
|
}
|
|
3073
3257
|
.ws-rail { position: fixed; inset: 0 auto 0 0; width: var(--ws-rail-w-collapsed); z-index: 40; }
|
|
3074
|
-
.ws-
|
|
3075
|
-
.ws-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
.ws-
|
|
3080
|
-
.ws-
|
|
3258
|
+
.ws-rail .ws-rail-brand,
|
|
3259
|
+
.ws-rail .ws-rail-action-label,
|
|
3260
|
+
.ws-rail .ws-rail-item-label,
|
|
3261
|
+
.ws-rail .ws-rail-item-count,
|
|
3262
|
+
.ws-rail .ds-theme-toggle-label { display: none; }
|
|
3263
|
+
.ws-rail .ws-rail-item, .ws-rail .ws-rail-action { justify-content: center; gap: 0; }
|
|
3264
|
+
.ws-rail .ws-rail-head { justify-content: center; }
|
|
3265
|
+
/* Expand/collapse is meaningless on the icon strip. */
|
|
3266
|
+
.ws-rail-toggle { display: none; }
|
|
3267
|
+
.ws-rail-foot { display: flex; justify-content: center; }
|
|
3268
|
+
.ws-sessions { inset: 0 auto 0 var(--ws-rail-w-collapsed); }
|
|
3081
3269
|
.ws-content { grid-area: content; padding-left: var(--ws-rail-w-collapsed); }
|
|
3082
|
-
.ws-rail-collapsed .ws-rail-item-label, .ws-rail-collapsed .ws-rail-brand { display: none; }
|
|
3083
|
-
/* Tap-scrim behind an open drawer; dismiss on click. Hidden unless a drawer
|
|
3084
|
-
is open so it never blocks the content area on desktop. */
|
|
3085
|
-
/* Scrim is always present on mobile so it can FADE with the drawer instead of
|
|
3086
|
-
hard-appearing via a display toggle; pointer-events gate keeps it inert
|
|
3087
|
-
while closed. Reduced-motion users get the global transition kill -> instant. */
|
|
3088
|
-
.ws-scrim { display: block; opacity: 0; pointer-events: none; position: fixed; inset: 0; z-index: 41; background: color-mix(in srgb, var(--fg) 38%, transparent); transition: opacity var(--dur-base) var(--ease); }
|
|
3089
|
-
.ws-shell.ws-sessions-open .ws-scrim, .ws-shell.ws-pane-open .ws-scrim { opacity: 1; pointer-events: auto; }
|
|
3090
|
-
/* The mobile drawer-toggle affordances live in the crumb bar. */
|
|
3091
|
-
.ws-drawer-toggle { display: inline-flex; }
|
|
3092
3270
|
/* The Crumb's narrow collapse elsewhere keys on the .app @container, which
|
|
3093
3271
|
does not exist inside WorkspaceShell - mirror it here so the crumb bar
|
|
3094
3272
|
cannot overflow a narrow viewport (trail hides, leaf ellipsizes, the
|
|
@@ -3099,11 +3277,8 @@ input[type="password"]:not(:placeholder-shown) + .input-clear {
|
|
|
3099
3277
|
.ws-crumb .app-crumb .leaf { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
3100
3278
|
.ws-crumb .app-crumb .crumb-right { margin-left: 0; flex-wrap: wrap; min-width: 0; display: inline-flex; }
|
|
3101
3279
|
}
|
|
3102
|
-
/* Drawer toggles are mobile-only chrome; hidden on the desktop grid. */
|
|
3103
|
-
.ws-drawer-toggle { display: none; align-items: center; justify-content: center; width: 40px; height: 40px; border: none; background: none; color: var(--fg-2); cursor: pointer; border-radius: var(--r-1); }
|
|
3104
3280
|
.ws-drawer-toggle:hover { background: var(--bg-2); color: var(--fg); }
|
|
3105
3281
|
.ws-drawer-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
3106
|
-
.ws-scrim { display: none; }
|
|
3107
3282
|
|
|
3108
3283
|
/* ============================================================
|
|
3109
3284
|
Row title highlight, expanded-row actions, filter pills.
|