anentrypoint-design 0.0.322 → 0.0.324
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/README.md +22 -2
- package/app-shell.css +24 -4782
- package/colors_and_type.css +43 -0
- package/dist/247420.css +74 -3
- package/dist/247420.js +16 -16
- package/package.json +14 -8
- package/src/bootstrap.js +10 -1
- package/src/components/chat-message-parts.js +355 -0
- package/src/components/chat.js +23 -320
- package/src/components/data-density.js +15 -10
- package/src/components/files-modals.js +14 -2
- package/src/components/files.js +5 -1
- package/src/components/freddie/helpers.js +46 -8
- package/src/css/app-shell/base.css +157 -0
- package/src/css/app-shell/catalog-theme.css +144 -0
- package/src/css/app-shell/chat-basic.css +12 -0
- package/src/css/app-shell/chat-polish.css +459 -0
- package/src/css/app-shell/data-density.css +150 -0
- package/src/css/app-shell/files.css +709 -0
- package/src/css/app-shell/hero-content.css +407 -0
- package/src/css/app-shell/kits-appended.css +361 -0
- package/src/css/app-shell/loading-alerts.css +120 -0
- package/src/css/app-shell/panel-row.css +177 -0
- package/src/css/app-shell/primitives.css +197 -0
- package/src/css/app-shell/responsive.css +266 -0
- package/src/css/app-shell/responsive2-workspace.css +465 -0
- package/src/css/app-shell/row-print.css +75 -0
- package/src/css/app-shell/sidebar-misc.css +79 -0
- package/src/css/app-shell/states-interactions.css +696 -0
- package/src/css/app-shell/topbar.css +319 -0
- package/src/deck-stage.js +6 -4
- package/src/highlight.js +20 -4
- package/src/index.js +15 -5
- package/src/kits/os/freddie/pages-chat.js +1 -1
- package/src/kits/os/freddie/pages-core.js +1 -1
- package/src/kits/os/freddie/pages-os.js +1 -1
- package/src/kits/os/freddie/pages-tools.js +1 -1
- package/src/kits/os/wm.js +38 -0
- package/src/kits/slides/deck-stage-overlay.js +68 -0
- package/src/kits/slides/deck-stage-state.js +81 -0
- package/src/kits/slides/deck-stage-style.js +117 -0
- package/src/kits/slides/deck-stage.js +167 -0
- package/src/kits/slides/index.js +5 -0
- package/src/markdown.js +89 -11
- package/src/kits/os/freddie/helpers.js +0 -33
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Responsive Perfection — Drawer rail, ultrawide cap, mobile compact
|
|
3
|
+
============================================================ */
|
|
4
|
+
|
|
5
|
+
/* Tablet + Mobile: side rail becomes off-canvas drawer (≤900px) */
|
|
6
|
+
/* Sidebar drawer collapse keys on the SHELL width (@container on .app, which is
|
|
7
|
+
container-type:inline-size) — NOT the viewport. Full-page (freddie) the shell
|
|
8
|
+
== viewport so this is identical to the old @media(max-width:900px); embedded
|
|
9
|
+
in a thebird WM window the drawer + hamburger appear when the WINDOW is narrow
|
|
10
|
+
even on a wide desktop. Drawer/scrim/toggle are absolute (anchored to .app), so
|
|
11
|
+
they overlay the window, not the page. */
|
|
12
|
+
@container (max-width: 900px) {
|
|
13
|
+
.app-body,
|
|
14
|
+
.app-body.no-side { grid-template-columns: 1fr !important; }
|
|
15
|
+
.app-side-shell {
|
|
16
|
+
position: absolute;
|
|
17
|
+
/* Full-height overlay drawer: the merged .app-chrome wraps and its real
|
|
18
|
+
height drifts from --app-topbar-h, so anchoring below it misplaces the
|
|
19
|
+
drawer. Overlay the chrome instead (z above --z-header), like ws drawers. */
|
|
20
|
+
left: 0; top: 0;
|
|
21
|
+
height: 100%;
|
|
22
|
+
width: 280px; max-width: 80%;
|
|
23
|
+
transform: translateX(-100%);
|
|
24
|
+
transition: transform var(--dur-base, 240ms) var(--ease, ease);
|
|
25
|
+
/* Above the sticky chrome (z-header): scrim > chrome > content budget. */
|
|
26
|
+
z-index: calc(var(--z-header, 100) + 2);
|
|
27
|
+
background: var(--bg);
|
|
28
|
+
border-right: 1px solid color-mix(in oklab, var(--fg) 8%, transparent);
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
overscroll-behavior: contain;
|
|
31
|
+
}
|
|
32
|
+
/* Lock the content scroller while the drawer is open so touch pans don't
|
|
33
|
+
scroll the page behind the scrim. */
|
|
34
|
+
.app-body.side-open .app-main { overflow: hidden; }
|
|
35
|
+
.app-side-shell.open,
|
|
36
|
+
.app-side.open,
|
|
37
|
+
.app-body.side-open .app-side-shell { transform: translateX(0); }
|
|
38
|
+
.app-side {
|
|
39
|
+
flex-direction: column !important;
|
|
40
|
+
flex-wrap: nowrap !important;
|
|
41
|
+
gap: var(--space-2);
|
|
42
|
+
padding: var(--space-3);
|
|
43
|
+
font-size: var(--fs-sm);
|
|
44
|
+
}
|
|
45
|
+
.app-side a {
|
|
46
|
+
flex: 0 0 auto; min-width: 0;
|
|
47
|
+
grid-template-columns: 18px 1fr auto;
|
|
48
|
+
padding: 10px 12px;
|
|
49
|
+
}
|
|
50
|
+
.app-side .group { width: 100%; }
|
|
51
|
+
/* Keep the crumb on mobile — apps mount contextual controls (model picker,
|
|
52
|
+
actions, live status) in crumb-right, so hiding it strands them. Collapse
|
|
53
|
+
the breadcrumb trail/leaf instead and let the right cluster wrap. */
|
|
54
|
+
.app-crumb { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 8px 12px; }
|
|
55
|
+
.app-crumb > .sep, .app-crumb > span:not(.crumb-right):not(.leaf) { display: none; }
|
|
56
|
+
.app-crumb .crumb-right { margin-left: 0; }
|
|
57
|
+
.chat-head { padding: var(--space-2) var(--space-3) var(--space-2); margin-bottom: var(--space-2); }
|
|
58
|
+
.app-main { padding-left: var(--space-3); padding-right: var(--space-3); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Drawer scrim — absolute so it covers THIS shell, shown when drawer open and
|
|
62
|
+
the shell is narrow (@container on .app). */
|
|
63
|
+
.app-side-scrim {
|
|
64
|
+
display: none;
|
|
65
|
+
position: absolute; inset: 0;
|
|
66
|
+
background: color-mix(in oklab, var(--bg) 60%, transparent);
|
|
67
|
+
/* Above the sticky chrome so nav behind an open drawer is not clickable. */
|
|
68
|
+
z-index: calc(var(--z-header, 100) + 1);
|
|
69
|
+
}
|
|
70
|
+
@container (max-width: 900px) {
|
|
71
|
+
.app-body.side-open .app-side-scrim { display: block; }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Nav toggle (hamburger) — hidden when the shell is wide, shown when the shell
|
|
75
|
+
itself is narrow (@container on .app). Absolute so it sits in THIS shell's
|
|
76
|
+
topbar, not pinned to the viewport corner. */
|
|
77
|
+
.app-side-toggle {
|
|
78
|
+
display: none;
|
|
79
|
+
position: absolute; top: calc((var(--app-topbar-h) - 44px) / 2); left: 10px;
|
|
80
|
+
/* Above the sticky topbar/chrome (z-header) and the drawer/scrim so the
|
|
81
|
+
translucent blurred chrome never paints over or intercepts the toggle. */
|
|
82
|
+
z-index: calc(var(--z-header, 100) + 3);
|
|
83
|
+
/* 44x44 minimum hit area (WCAG 2.5.5 / Apple HIG) - 36px is below the
|
|
84
|
+
reliable-tap threshold on touch. */
|
|
85
|
+
width: 44px; height: 44px;
|
|
86
|
+
align-items: center; justify-content: center;
|
|
87
|
+
font-size: 18px; line-height: 1;
|
|
88
|
+
background: var(--bg-2); color: var(--fg);
|
|
89
|
+
border: 1px solid var(--rule, color-mix(in oklab, var(--fg) 12%, transparent));
|
|
90
|
+
border-radius: var(--r-1, 6px);
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
}
|
|
93
|
+
.app-side-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
94
|
+
@container (max-width: 900px) {
|
|
95
|
+
.app-side-toggle { display: inline-flex; }
|
|
96
|
+
.app-topbar .brand { margin-left: 44px; }
|
|
97
|
+
/* Merged-chrome layout (.app-chrome > .app-crumb) puts the breadcrumb, not
|
|
98
|
+
the topbar brand, at the left edge where the absolute-positioned toggle
|
|
99
|
+
sits — without this the crumb text renders directly under the button. */
|
|
100
|
+
.app-chrome > .app-crumb { margin-left: 44px; }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Desktop: the app shell is exactly viewport-height and contains its own
|
|
104
|
+
scroll, so only .app-main (and the side rail) scroll — never the page too.
|
|
105
|
+
Pinning .app to 100dvh + overflow:hidden is what prevents the double
|
|
106
|
+
scrollbar that a min-height:100vh shell + inner overflow:auto produces.
|
|
107
|
+
.app-body fills the gap between topbar/crumb and status via flex:1 rather
|
|
108
|
+
than a hand-computed calc() that drifts from the real chrome heights. */
|
|
109
|
+
@media (min-width: 901px) {
|
|
110
|
+
.app { height: 100dvh; min-height: 0; overflow: hidden; }
|
|
111
|
+
/* Embedded shell (freddie WM window) fills its container, not the viewport. */
|
|
112
|
+
.fd-root .app { height: 100%; overflow: visible; }
|
|
113
|
+
.app-body { min-height: 0; flex: 1 1 auto; }
|
|
114
|
+
.app-side-shell { overflow-y: auto; min-height: 0; }
|
|
115
|
+
.app-main { overflow-y: auto; min-height: 0; }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Mobile (≤480) status bar compact; hide tail item */
|
|
119
|
+
@media (max-width: 480px) {
|
|
120
|
+
.app-status {
|
|
121
|
+
font-size: var(--fs-micro);
|
|
122
|
+
padding: 4px var(--space-2);
|
|
123
|
+
gap: var(--space-2);
|
|
124
|
+
}
|
|
125
|
+
.app-status > :last-child:not(:only-child) { display: none; }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Tiny phone (≤360) topbar compact */
|
|
129
|
+
@media (max-width: 360px) {
|
|
130
|
+
.app-topbar {
|
|
131
|
+
padding: 8px var(--space-2);
|
|
132
|
+
font-size: var(--fs-xs);
|
|
133
|
+
gap: var(--space-2);
|
|
134
|
+
}
|
|
135
|
+
.app-topbar nav,
|
|
136
|
+
.app-topbar > :last-child { display: none; }
|
|
137
|
+
.brand { font-size: var(--fs-tiny); }
|
|
138
|
+
/* Slightly narrower drawer on tiny phones; max-width:80% remains the guard. */
|
|
139
|
+
.app-side-shell { width: 260px; }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ----------------------------------------------------------------------------
|
|
143
|
+
WorkspaceShell — Claude-Desktop / cowork three-column app shell.
|
|
144
|
+
Columns: [ws-rail] [ws-sessions?] [ws-content] [ws-pane?]
|
|
145
|
+
Collapse via .ws-rail-collapsed / .ws-pane-collapsed classes on .ws-shell.
|
|
146
|
+
All sizing/colour from kit tokens; no hardcoded palette.
|
|
147
|
+
---------------------------------------------------------------------------- */
|
|
148
|
+
.ws-shell {
|
|
149
|
+
/* Fluid chrome columns: shrink on small laptops, breathe on ultrawide, so the
|
|
150
|
+
~848px of fixed chrome no longer eats a constant slab. An inline --ws-*-w
|
|
151
|
+
written by a resize drag overrides these (inline wins), pinning the width. */
|
|
152
|
+
--ws-rail-w: clamp(200px, 16vw, 260px);
|
|
153
|
+
--ws-rail-w-collapsed: 60px;
|
|
154
|
+
--ws-sessions-w: clamp(248px, 22vw, 360px);
|
|
155
|
+
--ws-pane-w: clamp(288px, 24vw, 420px);
|
|
156
|
+
display: grid;
|
|
157
|
+
grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) 1fr var(--ws-pane-w);
|
|
158
|
+
grid-template-areas: "rail sessions content pane";
|
|
159
|
+
height: 100%;
|
|
160
|
+
min-height: 0;
|
|
161
|
+
background: var(--bg);
|
|
162
|
+
color: var(--fg);
|
|
163
|
+
}
|
|
164
|
+
.ws-shell.ws-no-sessions { grid-template-columns: var(--ws-rail-w) 1fr var(--ws-pane-w); grid-template-areas: "rail content pane"; }
|
|
165
|
+
.ws-shell.ws-no-pane.ws-no-sessions { grid-template-columns: var(--ws-rail-w) 1fr; grid-template-areas: "rail content"; }
|
|
166
|
+
.ws-shell.ws-no-pane:not(.ws-no-sessions) { grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) 1fr; grid-template-areas: "rail sessions content"; }
|
|
167
|
+
/* G1 stable frame: when a tab has no pane but asks to keep the column geometry
|
|
168
|
+
(ws-no-pane + ws-pane-collapsed), KEEP the 4-track grid with the pane track
|
|
169
|
+
at width 0 instead of collapsing to a 3-track layout - so the shell does not
|
|
170
|
+
re-flow its column count on tab switch. The pane track stays present (0px),
|
|
171
|
+
so chat/history/files/live/settings share one geometry. */
|
|
172
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions) { grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) 1fr var(--ws-pane-w); grid-template-areas: "rail sessions content pane"; }
|
|
173
|
+
.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"; }
|
|
174
|
+
.ws-shell.ws-rail-collapsed { --ws-rail-w: var(--ws-rail-w-collapsed); }
|
|
175
|
+
.ws-shell.ws-pane-collapsed { --ws-pane-w: 0px; }
|
|
176
|
+
/* Sessions column desktop collapse (parity with the pane collapse), reclaiming
|
|
177
|
+
its width for a full-width thread/grid. */
|
|
178
|
+
.ws-shell.ws-sessions-collapsed { --ws-sessions-w: 0px; }
|
|
179
|
+
.ws-sessions-collapsed .ws-sessions { overflow: hidden; border-right: none; }
|
|
180
|
+
.ws-sessions-collapsed .ws-sessions > * { display: none; }
|
|
181
|
+
/* Column resize handles: a thin keyboard-accessible separator pinned to the
|
|
182
|
+
right edge of each chrome track; drag (or ArrowLeft/Right) writes a clamped
|
|
183
|
+
inline --ws-*-w. */
|
|
184
|
+
.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; }
|
|
185
|
+
.ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background: transparent; transition: background var(--dur-snap) var(--ease); }
|
|
186
|
+
.ws-resizer:hover::after, .ws-resizer:focus-visible::after { background: var(--accent); }
|
|
187
|
+
.ws-resizer:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
188
|
+
.ws-resizer.ws-resizer-rail { grid-column: 1; }
|
|
189
|
+
.ws-resizer.ws-resizer-sessions { grid-column: 2; }
|
|
190
|
+
.ws-resizer.ws-resizer-pane { grid-column: 3; justify-self: end; }
|
|
191
|
+
/* A resizer must vanish once its TRACK is removed by the staging media blocks,
|
|
192
|
+
else dragging it writes a --ws-*-w var that no longer affects the now-fixed
|
|
193
|
+
drawer (a dead handle). Mirror the 1480 / 1100 / 900 staging exactly. */
|
|
194
|
+
@media (max-width: 1480px) { .ws-resizer.ws-resizer-pane { display: none; } }
|
|
195
|
+
@media (max-width: 1100px) { .ws-resizer.ws-resizer-sessions { display: none; } }
|
|
196
|
+
@media (max-width: 900px) { .ws-resizer { display: none; } }
|
|
197
|
+
/* A resizer must also vanish once its TRACK is desktop-collapsed: a 0px (pane/
|
|
198
|
+
sessions) or 60px icon-only (rail) track has no width to drag, and a drag would
|
|
199
|
+
write an INLINE --ws-*-w that overrides the collapse var (inline wins), fighting
|
|
200
|
+
the collapse state. Mirror the breakpoint guards for the collapse classes. */
|
|
201
|
+
.ws-rail-collapsed .ws-resizer-rail,
|
|
202
|
+
.ws-sessions-collapsed .ws-resizer-sessions,
|
|
203
|
+
.ws-pane-collapsed .ws-resizer-pane { display: none; }
|
|
204
|
+
/* Coarse-pointer hit target for hybrid touch laptops above the drawer breakpoint
|
|
205
|
+
(the 8px sliver is un-grabbable by touch). */
|
|
206
|
+
@media (pointer: coarse) { .ws-resizer { width: 16px; margin-right: -8px; } }
|
|
207
|
+
/* Ease the rail/pane collapse. Track COUNT stays stable on collapse (only a
|
|
208
|
+
width var flips), so grid-template-columns is animatable; reduced-motion
|
|
209
|
+
drops it to an instant swap. */
|
|
210
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
211
|
+
.ws-shell { transition: grid-template-columns var(--dur-base) var(--ease); }
|
|
212
|
+
}
|
|
213
|
+
/* Ultrawide: cap the shell so the 1fr content track doesn't stretch to
|
|
214
|
+
unreadable measures while the fixed side columns pin to their clamps. */
|
|
215
|
+
@media (min-width: 1920px) {
|
|
216
|
+
.ws-shell { max-width: 1920px; margin-inline: auto; }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Rail (left nav) */
|
|
220
|
+
.ws-rail {
|
|
221
|
+
grid-area: rail;
|
|
222
|
+
position: relative;
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
min-height: 0;
|
|
226
|
+
background: var(--bg-2);
|
|
227
|
+
border-right: var(--bw-hair) solid var(--bg-3);
|
|
228
|
+
overflow: hidden;
|
|
229
|
+
transition: width var(--dur-base) var(--ease);
|
|
230
|
+
}
|
|
231
|
+
.ws-rail-toggle {
|
|
232
|
+
position: absolute; top: var(--space-2); right: var(--space-2);
|
|
233
|
+
width: 36px; height: 36px;
|
|
234
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
235
|
+
background: transparent; border: none; color: var(--fg-2);
|
|
236
|
+
border-radius: var(--r-1); cursor: pointer;
|
|
237
|
+
}
|
|
238
|
+
.ws-rail-toggle:hover { background: var(--bg-3); color: var(--fg); }
|
|
239
|
+
.ws-rail-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
240
|
+
.ws-rail-inner { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: var(--space-3) var(--space-2); gap: var(--space-2); }
|
|
241
|
+
.ws-rail-head { display: flex; align-items: center; min-height: 36px; padding: 0 var(--space-2); }
|
|
242
|
+
.ws-rail-brand { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-body); color: var(--fg); white-space: nowrap; overflow: hidden; }
|
|
243
|
+
.ws-rail-action {
|
|
244
|
+
display: flex; align-items: center; gap: var(--space-2);
|
|
245
|
+
padding: var(--space-2) var(--space-3); margin: var(--space-1) 0;
|
|
246
|
+
background: var(--accent); color: var(--accent-fg, var(--bg));
|
|
247
|
+
border: none; border-radius: var(--r-1); cursor: pointer;
|
|
248
|
+
font-family: var(--ff-body); font-size: var(--fs-sm); font-weight: 600;
|
|
249
|
+
min-height: 40px; white-space: nowrap; overflow: hidden;
|
|
250
|
+
}
|
|
251
|
+
.ws-rail-action:hover { filter: brightness(0.92); }
|
|
252
|
+
.ws-rail-action:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
253
|
+
.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; }
|
|
254
|
+
.ws-rail-item {
|
|
255
|
+
display: flex; align-items: center; gap: var(--space-2);
|
|
256
|
+
width: 100%; padding: var(--space-2); min-height: 44px;
|
|
257
|
+
background: transparent; border: none; color: var(--fg-2);
|
|
258
|
+
border-radius: var(--r-1); cursor: pointer; text-align: left;
|
|
259
|
+
font-family: var(--ff-body); font-size: var(--fs-sm); white-space: nowrap; overflow: hidden;
|
|
260
|
+
}
|
|
261
|
+
.ws-rail-item:hover { background: var(--bg-3); color: var(--fg); }
|
|
262
|
+
.ws-rail-item:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
263
|
+
.ws-rail-item.active { background: var(--accent-tint); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
|
|
264
|
+
.ws-rail-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
|
|
265
|
+
.ws-rail-item-count { font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
266
|
+
.ws-rail-item-flag { width: 6px; height: 6px; border-radius: 50%; flex: none; }
|
|
267
|
+
.ws-rail-item-flag.tone-flame { background: var(--flame); box-shadow: 0 0 0 2px color-mix(in oklab, var(--flame) 38%, transparent); }
|
|
268
|
+
.ws-rail-foot { margin-top: auto; padding-top: var(--space-2); border-top: var(--bw-hair) solid var(--bg-3); }
|
|
269
|
+
|
|
270
|
+
/* Collapsed rail: icon-only — hide text labels, center icons, drop toggle's far-right pin */
|
|
271
|
+
.ws-rail-collapsed .ws-rail-brand,
|
|
272
|
+
.ws-rail-collapsed .ws-rail-action-label,
|
|
273
|
+
.ws-rail-collapsed .ws-rail-item-label,
|
|
274
|
+
.ws-rail-collapsed .ws-rail-item-count { display: none; }
|
|
275
|
+
.ws-rail-collapsed .ws-rail-item,
|
|
276
|
+
.ws-rail-collapsed .ws-rail-action { justify-content: center; gap: 0; }
|
|
277
|
+
.ws-rail-collapsed .ws-rail-head { justify-content: center; }
|
|
278
|
+
|
|
279
|
+
/* Sessions column */
|
|
280
|
+
.ws-sessions {
|
|
281
|
+
grid-area: sessions;
|
|
282
|
+
min-height: 0; display: flex; flex-direction: column;
|
|
283
|
+
/* Rail and pane both sit on --bg-2 (a recessed plane framing the elevated
|
|
284
|
+
--bg content column); sessions used flat --bg instead, so the
|
|
285
|
+
conversation list and the chat thread read as the SAME surface with only
|
|
286
|
+
a 1px hairline between them - the flattest, most "one big beige box"
|
|
287
|
+
tell in the shell. --bg-2 restores the three-plane depth (rail/sessions
|
|
288
|
+
recessed either side, content elevated in the middle) the design
|
|
289
|
+
already establishes everywhere else. */
|
|
290
|
+
background: var(--bg-2); border-right: var(--bw-hair) solid var(--bg-3);
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
}
|
|
293
|
+
.ws-no-sessions .ws-sessions { display: none; }
|
|
294
|
+
|
|
295
|
+
/* Content column */
|
|
296
|
+
.ws-content { grid-area: content; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
297
|
+
/* Crumb band is the top chrome of the content column: a stable height so the
|
|
298
|
+
top edge aligns with the rail head, and a left gutter matching .ws-main so
|
|
299
|
+
the trail text is not flush against the rail border. */
|
|
300
|
+
.ws-crumb { flex: 0 0 auto; min-height: calc(var(--app-crumb-h) + var(--space-3)); padding: 0 var(--space-5); display: flex; align-items: center; gap: var(--space-1); border-bottom: var(--bw-hair) solid var(--bg-3); }
|
|
301
|
+
.ws-crumb-main { flex: 1 1 auto; min-width: 0; }
|
|
302
|
+
/* Content column gutter. Claude-Code-class calm: file grid / dashboard / event
|
|
303
|
+
list / history get a generous, consistent inner gutter instead of butting
|
|
304
|
+
against the 1px column borders. The chat tab opts out via .ws-main--flush
|
|
305
|
+
because the chat thread carries its own --measure gutter. */
|
|
306
|
+
.ws-main { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; padding: var(--space-4) var(--space-5); }
|
|
307
|
+
.ws-main.ws-main--flush { padding: 0; }
|
|
308
|
+
.ws-main:focus { outline: none; }
|
|
309
|
+
|
|
310
|
+
/* Right context pane */
|
|
311
|
+
.ws-pane {
|
|
312
|
+
grid-area: pane; position: relative;
|
|
313
|
+
min-height: 0; display: flex; flex-direction: column;
|
|
314
|
+
background: var(--bg-2); border-left: var(--bw-hair) solid var(--bg-3);
|
|
315
|
+
overflow: hidden; transition: width var(--dur-base) var(--ease);
|
|
316
|
+
overscroll-behavior: contain;
|
|
317
|
+
}
|
|
318
|
+
.ws-pane-collapsed .ws-pane { width: 0; border-left: none; }
|
|
319
|
+
.ws-pane-collapsed .ws-pane > * { display: none; }
|
|
320
|
+
@media (pointer: coarse) {
|
|
321
|
+
.ws-rail-toggle { width: 44px; height: 44px; }
|
|
322
|
+
.ws-drawer-toggle { width: 44px; height: 44px; }
|
|
323
|
+
.ws-desktop-toggle { width: 44px; height: 44px; }
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Drawer toggles and the scrim are hidden by default and revealed by the staged
|
|
327
|
+
media blocks BELOW - these base rules must precede those blocks in source
|
|
328
|
+
order: at equal specificity the later rule wins regardless of media, so a
|
|
329
|
+
trailing display:none silently kills every drawer affordance (shipped bug:
|
|
330
|
+
the mobile drawers were dead because these lines used to sit last). */
|
|
331
|
+
.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); }
|
|
332
|
+
/* Desktop-only chrome toggle (sessions collapse): inverse of the mobile drawer-toggle. */
|
|
333
|
+
.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); }
|
|
334
|
+
.ws-desktop-toggle:hover { background: var(--bg-2); color: var(--fg); }
|
|
335
|
+
.ws-desktop-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
336
|
+
@media (max-width: 900px) { .ws-desktop-toggle { display: none; } }
|
|
337
|
+
/* The pane collapse toggle is meaningless once the pane TRACK is dropped (the
|
|
338
|
+
pane becomes a mobile overlay drawer at <=1480px, reached via its own
|
|
339
|
+
drawer-toggle), so hide this crumb control past that breakpoint. */
|
|
340
|
+
@media (max-width: 1480px) { .ws-pane-toggle { display: none; } }
|
|
341
|
+
@media (max-width: 480px) { .ds-247420 .ws-crumb { padding-left: var(--space-2); padding-right: var(--space-2); } }
|
|
342
|
+
.ws-scrim { display: none; }
|
|
343
|
+
|
|
344
|
+
/* Responsive: the columns yield to the CONTENT in stages - the main column is
|
|
345
|
+
the product, so the right pane gives way first, the sessions list second,
|
|
346
|
+
and only below 900px does the rail itself drop to a fixed icon strip. Yielded
|
|
347
|
+
columns stay reachable as overlay drawers (.ws-pane-open / .ws-sessions-open,
|
|
348
|
+
toggled from the crumb bar) over a shared fade scrim. Before this staging the
|
|
349
|
+
4-track grid survived down to 901px and crushed the chat thread to ~245px
|
|
350
|
+
while the 320px context pane kept its full width. */
|
|
351
|
+
|
|
352
|
+
/* Stage 1 (<=1480px): drop the pane TRACK; the context pane becomes a right
|
|
353
|
+
overlay drawer. */
|
|
354
|
+
@media (max-width: 1480px) {
|
|
355
|
+
.ws-shell,
|
|
356
|
+
.ws-shell.ws-no-pane,
|
|
357
|
+
.ws-shell.ws-pane-collapsed,
|
|
358
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions) {
|
|
359
|
+
grid-template-columns: var(--ws-rail-w) var(--ws-sessions-w) minmax(0, 1fr);
|
|
360
|
+
grid-template-areas: "rail sessions content";
|
|
361
|
+
}
|
|
362
|
+
.ws-shell.ws-no-sessions,
|
|
363
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
364
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
365
|
+
grid-template-columns: var(--ws-rail-w) minmax(0, 1fr);
|
|
366
|
+
grid-template-areas: "rail content";
|
|
367
|
+
}
|
|
368
|
+
/* Drawer width is a literal: --ws-pane-w is 0px while pane-collapsed, and a
|
|
369
|
+
desktop-collapsed pane must still open as a full drawer. */
|
|
370
|
+
.ws-pane {
|
|
371
|
+
position: fixed; inset: 0 0 0 auto;
|
|
372
|
+
width: min(340px, 85vw);
|
|
373
|
+
z-index: 42; transform: translateX(110%);
|
|
374
|
+
transition: transform var(--dur-base) var(--ease);
|
|
375
|
+
}
|
|
376
|
+
.ws-shell.ws-pane-open .ws-pane { transform: translateX(0); width: min(340px, 85vw); }
|
|
377
|
+
.ws-shell.ws-pane-open.ws-pane-collapsed .ws-pane { border-left: var(--bw-hair) solid var(--bg-3); }
|
|
378
|
+
.ws-shell.ws-pane-open.ws-pane-collapsed .ws-pane > * { display: revert; }
|
|
379
|
+
.ws-pane-drawer-toggle { display: inline-flex; }
|
|
380
|
+
/* Scrim is always present from this stage down so it FADES with the drawer
|
|
381
|
+
instead of hard-appearing; pointer-events gate keeps it inert while closed. */
|
|
382
|
+
.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); }
|
|
383
|
+
.ws-shell.ws-sessions-open .ws-scrim, .ws-shell.ws-pane-open .ws-scrim { opacity: 1; pointer-events: auto; }
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* Stage 2 (<=1100px): drop the sessions TRACK; the conversation list becomes a
|
|
387
|
+
left overlay drawer. */
|
|
388
|
+
@media (max-width: 1100px) {
|
|
389
|
+
.ws-shell,
|
|
390
|
+
.ws-shell.ws-no-pane,
|
|
391
|
+
.ws-shell.ws-pane-collapsed,
|
|
392
|
+
.ws-shell.ws-no-sessions,
|
|
393
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
394
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions),
|
|
395
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
396
|
+
grid-template-columns: var(--ws-rail-w) minmax(0, 1fr);
|
|
397
|
+
grid-template-areas: "rail content";
|
|
398
|
+
}
|
|
399
|
+
.ws-sessions {
|
|
400
|
+
position: fixed; inset: 0 auto 0 0;
|
|
401
|
+
/* Immune to the desktop collapse var (--ws-sessions-w:0px persisted from
|
|
402
|
+
a desktop session would open an invisible 0-width drawer). */
|
|
403
|
+
width: min(max(var(--ws-sessions-w), 280px), 80vw);
|
|
404
|
+
z-index: 42; transform: translateX(-110%);
|
|
405
|
+
transition: transform var(--dur-base) var(--ease);
|
|
406
|
+
border-right: var(--bw-hair) solid var(--bg-3);
|
|
407
|
+
overscroll-behavior: contain;
|
|
408
|
+
}
|
|
409
|
+
.ws-shell.ws-sessions-open .ws-sessions { transform: translateX(0); }
|
|
410
|
+
/* Drawer mode ignores the desktop collapsed state: children stay rendered
|
|
411
|
+
and the border returns, so a persisted collapse can't blank the drawer. */
|
|
412
|
+
.ws-shell.ws-sessions-collapsed .ws-sessions > * { display: revert; }
|
|
413
|
+
.ws-shell.ws-sessions-collapsed .ws-sessions { border-right: var(--bw-hair) solid var(--bg-3); }
|
|
414
|
+
.ws-sessions-drawer-toggle { display: inline-flex; }
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Stage 3 (<=900px): single content column; the rail drops to a fixed icon-only
|
|
418
|
+
strip. Labels hide UNCONDITIONALLY here - a 60px rail showing clipped label
|
|
419
|
+
text ('age', 'Ne') is the worst of both worlds. */
|
|
420
|
+
@media (max-width: 900px) {
|
|
421
|
+
.ws-shell,
|
|
422
|
+
.ws-shell.ws-no-sessions,
|
|
423
|
+
.ws-shell.ws-no-pane,
|
|
424
|
+
.ws-shell.ws-pane-collapsed,
|
|
425
|
+
.ws-shell.ws-no-pane.ws-no-sessions,
|
|
426
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed:not(.ws-no-sessions),
|
|
427
|
+
.ws-shell.ws-no-pane.ws-pane-collapsed.ws-no-sessions {
|
|
428
|
+
grid-template-columns: minmax(0, 1fr);
|
|
429
|
+
grid-template-areas: "content";
|
|
430
|
+
}
|
|
431
|
+
.ws-rail { position: fixed; inset: 0 auto 0 0; width: var(--ws-rail-w-collapsed); z-index: 40; }
|
|
432
|
+
.ws-rail .ws-rail-brand,
|
|
433
|
+
.ws-rail .ws-rail-action-label,
|
|
434
|
+
.ws-rail .ws-rail-item-label,
|
|
435
|
+
.ws-rail .ws-rail-item-count,
|
|
436
|
+
.ws-rail .ds-theme-toggle-label { display: none; }
|
|
437
|
+
.ws-rail .ws-rail-item, .ws-rail .ws-rail-action { justify-content: center; gap: 0; }
|
|
438
|
+
.ws-rail .ws-rail-head { justify-content: center; }
|
|
439
|
+
/* Expand/collapse is meaningless on the icon strip. */
|
|
440
|
+
.ws-rail-toggle { display: none; }
|
|
441
|
+
.ws-rail-foot { display: flex; justify-content: center; }
|
|
442
|
+
/* The 1100px rule's closed-state translateX(-110%) was sized for left:0;
|
|
443
|
+
once left shifts to the collapsed rail width, -110% no longer clears the
|
|
444
|
+
viewport and leaves a sliver of the "closed" drawer visible on screen. */
|
|
445
|
+
.ws-sessions { inset: 0 auto 0 var(--ws-rail-w-collapsed); transform: translateX(calc(-100% - var(--ws-rail-w-collapsed))); }
|
|
446
|
+
.ws-shell.ws-sessions-open .ws-sessions { transform: translateX(0); }
|
|
447
|
+
.ws-content { grid-area: content; padding-left: var(--ws-rail-w-collapsed); }
|
|
448
|
+
/* The Crumb's narrow collapse elsewhere keys on the .app @container, which
|
|
449
|
+
does not exist inside WorkspaceShell - mirror it here so the crumb bar
|
|
450
|
+
cannot overflow a narrow viewport (trail hides, leaf ellipsizes, the
|
|
451
|
+
right cluster wraps under instead of pushing past the edge). */
|
|
452
|
+
.ws-crumb { padding-top: 6px; padding-bottom: 6px; }
|
|
453
|
+
.ws-crumb .app-crumb { flex-wrap: wrap; min-width: 0; }
|
|
454
|
+
.ws-crumb .app-crumb > .sep, .ws-crumb .app-crumb > span:not(.crumb-right):not(.leaf) { display: none; }
|
|
455
|
+
.ws-crumb .app-crumb .leaf { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
456
|
+
.ws-crumb .app-crumb .crumb-right { margin-left: 0; flex-wrap: wrap; min-width: 0; display: inline-flex; }
|
|
457
|
+
}
|
|
458
|
+
.ws-drawer-toggle:hover { background: var(--bg-2); color: var(--fg); }
|
|
459
|
+
.ws-drawer-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
460
|
+
|
|
461
|
+
@media (prefers-reduced-motion: reduce) {
|
|
462
|
+
.ws-shell, .ws-rail, .ws-pane, .ws-sessions, .ws-scrim { transition: none; }
|
|
463
|
+
.ws-resizer::after { transition: none; }
|
|
464
|
+
}
|
|
465
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Row title highlight, expanded-row actions, filter pills.
|
|
3
|
+
============================================================ */
|
|
4
|
+
|
|
5
|
+
/* Highlighted match inside a Row title (Row `highlight` prop). */
|
|
6
|
+
.ds-hl { background: color-mix(in oklab, var(--accent) 25%, transparent); color: inherit; border-radius: var(--r-hair); }
|
|
7
|
+
|
|
8
|
+
/* Action strip rendered inside an EXPANDED Row (Row `actions` prop). The
|
|
9
|
+
buttons stop propagation so they never fire the row onClick. */
|
|
10
|
+
.row-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); width: 100%; padding-top: var(--space-2); }
|
|
11
|
+
.row-act {
|
|
12
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
13
|
+
padding: 4px 10px; min-height: 28px;
|
|
14
|
+
background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1);
|
|
15
|
+
color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-tiny); cursor: pointer;
|
|
16
|
+
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
17
|
+
}
|
|
18
|
+
.row-act:hover { background: var(--bg-3); color: var(--fg); }
|
|
19
|
+
.row-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
20
|
+
|
|
21
|
+
/* FilterPills - a group of pill toggle buttons (aria-pressed). */
|
|
22
|
+
.ds-filter-pills { display: flex; flex-wrap: wrap; gap: var(--space-2); }
|
|
23
|
+
.ds-filter-pill {
|
|
24
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
25
|
+
padding: 4px 12px; min-height: 28px;
|
|
26
|
+
background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-pill);
|
|
27
|
+
color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-tiny); cursor: pointer;
|
|
28
|
+
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
29
|
+
}
|
|
30
|
+
.ds-filter-pill:hover { background: var(--bg-3); color: var(--fg); }
|
|
31
|
+
.ds-filter-pill.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
|
|
32
|
+
.ds-filter-pill:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
33
|
+
|
|
34
|
+
/* Touch floor for the new small controls. */
|
|
35
|
+
@media (pointer: coarse) {
|
|
36
|
+
.row-act, .ds-filter-pill { min-height: 44px; }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Disabled file actions (read-only row / in-flight mutation) stay visible but inert. */
|
|
40
|
+
.ds-file-act:disabled { opacity: .45; cursor: default; }
|
|
41
|
+
.ds-file-act:disabled:hover { background: transparent; color: var(--fg-3); }
|
|
42
|
+
.ds-file-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
43
|
+
|
|
44
|
+
/* ============================================================
|
|
45
|
+
Print — linearize WorkspaceShell so main content prints in full.
|
|
46
|
+
The multi-column CSS grid with overflow:auto regions clips at
|
|
47
|
+
the on-screen height in print/PDF; drop all chrome and let
|
|
48
|
+
.ws-main expand to its natural document height.
|
|
49
|
+
============================================================ */
|
|
50
|
+
@media print {
|
|
51
|
+
.ws-shell { display: block; }
|
|
52
|
+
.ws-rail,
|
|
53
|
+
.ws-sessions,
|
|
54
|
+
.ws-pane,
|
|
55
|
+
.ws-crumb,
|
|
56
|
+
.app-status { display: none; }
|
|
57
|
+
.ws-main { overflow: visible; height: auto; }
|
|
58
|
+
/* AppShell: unpin the viewport-height frame so content flows across pages,
|
|
59
|
+
and drop all chrome (it prints as page furniture otherwise). */
|
|
60
|
+
.app { height: auto; min-height: 0; overflow: visible; display: block; }
|
|
61
|
+
.app-body { display: block; }
|
|
62
|
+
.app-main { overflow: visible; height: auto; display: block; max-width: 100%; }
|
|
63
|
+
.app-topbar, .app-chrome, .app-crumb, .app-side-shell, .app-side-scrim,
|
|
64
|
+
.app-side-toggle, .btn-fab, .skip-link, .ds-marquee { display: none; }
|
|
65
|
+
/* Modals/preview: print the content, not a blurred overlay clipped to one page. */
|
|
66
|
+
.ds-modal-backdrop { position: static; background: none; backdrop-filter: none; padding: 0; }
|
|
67
|
+
.ds-modal, .ds-modal-preview { max-width: 100%; max-height: none; box-shadow: none; }
|
|
68
|
+
.ds-modal-body, .ds-preview-body, .ds-preview-code, .ds-preview-text { overflow: visible; }
|
|
69
|
+
.ds-modal-actions, .ds-preview-actions { display: none; }
|
|
70
|
+
/* Data-density: fixed-height log clips; bg-only tiles lose their boundary. */
|
|
71
|
+
.ds-live-log { height: auto; max-height: none; overflow: visible; }
|
|
72
|
+
.ds-stat, .kpi-card { border: 1px solid var(--rule); }
|
|
73
|
+
.ds-session-row { break-inside: avoid; }
|
|
74
|
+
}
|
|
75
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Sidebar polish: hide zero-count badges; tonal active state;
|
|
3
|
+
monospace count chips.
|
|
4
|
+
============================================================ */
|
|
5
|
+
.app-side .count {
|
|
6
|
+
padding: 1px 8px; font-size: var(--fs-micro); font-weight: 700;
|
|
7
|
+
font-family: var(--ff-mono); letter-spacing: 0.04em;
|
|
8
|
+
min-width: 18px; text-align: center;
|
|
9
|
+
}
|
|
10
|
+
.app-side a:has(> .count:empty) > .count,
|
|
11
|
+
.app-side .count:empty { display: none; }
|
|
12
|
+
.app-side a .glyph { font-family: var(--ff-mono); font-size: 13px; font-weight: 600; color: var(--fg-3); text-align: center; }
|
|
13
|
+
.app-side a.active .glyph { color: var(--accent-ink); }
|
|
14
|
+
|
|
15
|
+
/* -- select primitive --------------------------------------------------- */
|
|
16
|
+
.ds-select {
|
|
17
|
+
width: 100%;
|
|
18
|
+
min-width: 0;
|
|
19
|
+
min-height: 32px; /* shared control floor with .btn/.btn-primary/.btn-ghost */
|
|
20
|
+
padding: 10px 30px 10px 14px; /* right gap clears the chevron */
|
|
21
|
+
background: var(--bg-2);
|
|
22
|
+
border: 0;
|
|
23
|
+
border-radius: var(--r-2);
|
|
24
|
+
font-family: inherit;
|
|
25
|
+
font-size: var(--fs-sm);
|
|
26
|
+
color: var(--fg);
|
|
27
|
+
/* Clip long option text gracefully - a select that cuts 'Claude Sonnet
|
|
28
|
+
(latest' mid-parenthesis reads as broken; ellipsis reads as truncated. */
|
|
29
|
+
text-overflow: ellipsis;
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
appearance: none;
|
|
33
|
+
background-image: linear-gradient(45deg, transparent 50%, var(--fg-3) 50%),
|
|
34
|
+
linear-gradient(135deg, var(--fg-3) 50%, transparent 50%);
|
|
35
|
+
background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
|
|
36
|
+
background-size: 5px 5px, 5px 5px;
|
|
37
|
+
background-repeat: no-repeat;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
}
|
|
40
|
+
.ds-select:focus-visible { box-shadow: var(--focus-ring-inset); }
|
|
41
|
+
.ds-select:hover { background-color: var(--bg-3); }
|
|
42
|
+
|
|
43
|
+
/* -- chat composer autogrow polish (sizing lives in the primary block) -- */
|
|
44
|
+
.chat-composer textarea {
|
|
45
|
+
transition: height var(--dur-snap) var(--ease);
|
|
46
|
+
}
|
|
47
|
+
.chat-composer textarea:disabled {
|
|
48
|
+
opacity: 0.5;
|
|
49
|
+
cursor: not-allowed;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* -- mobile responsive: chat -------------------------------------------- */
|
|
53
|
+
@media (max-width: 768px) {
|
|
54
|
+
.chat-stack { max-width: 100%; }
|
|
55
|
+
.chat-msg { padding: 4px 0; }
|
|
56
|
+
.chat-msg:hover { padding: 4px 0; margin: 0; border-radius: 0; background: transparent; }
|
|
57
|
+
.chat-bubble { font-size: var(--fs-sm); padding: 10px 14px; }
|
|
58
|
+
.chat-avatar { width: 28px; height: 28px; font-size: 12px; }
|
|
59
|
+
.chat-composer { padding: 8px; }
|
|
60
|
+
.chat-composer textarea { padding: 10px 12px; }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* --- landscape orientation: reduce vertical space for chrome + composer --- */
|
|
64
|
+
@media (max-height: 500px) and (orientation: landscape) {
|
|
65
|
+
/* Keep horizontal padding: 0 put the textarea/focus ring flush on the edge. */
|
|
66
|
+
.chat-composer { padding: 6px var(--space-2); }
|
|
67
|
+
.chat-composer textarea { min-height: 36px; max-height: 96px; }
|
|
68
|
+
.chat-composer .chat-composer-hint,
|
|
69
|
+
.chat-composer .chat-composer-context { display: none; }
|
|
70
|
+
/* Compact the shell chrome: ~114px of topbar+crumb+status is a third of a
|
|
71
|
+
360px-tall landscape fold. */
|
|
72
|
+
:root { --app-topbar-h: 40px; --app-crumb-h: 24px; }
|
|
73
|
+
.app-chrome { padding: 4px var(--pad-x); }
|
|
74
|
+
.app-status { display: none; }
|
|
75
|
+
.ws-crumb { min-height: 32px; }
|
|
76
|
+
.ds-hero { padding: var(--space-4) 0 var(--space-3); }
|
|
77
|
+
.ds-hero-title { font-size: clamp(28px, 6cqi, 56px); }
|
|
78
|
+
}
|
|
79
|
+
|