@tiagojct/subsub 0.6.1 → 0.8.0

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/web/app.css CHANGED
@@ -1,256 +1,870 @@
1
- /* Sub-Sub web view. Glauca tokens (glauca.css); the librarian gets the Try-Works orange. */
1
+ /* Sub-Sub web view.
2
+ Type: IBM Plex Sans for the interface, IBM Plex Serif for replies, IBM Plex Mono for commands.
3
+ The fonts are local: the page's CSP allows no other origin. */
2
4
 
3
- @font-face { font-family: "IBM Plex Sans"; src: url("/fonts/IBMPlexSans.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
5
+ @font-face { font-family: "IBM Plex Sans"; src: url("/fonts/IBMPlexSans.woff2") format("woff2"); font-weight: 100 700; font-stretch: 75% 100%; font-display: swap; }
4
6
  @font-face { font-family: "IBM Plex Serif"; src: url("/fonts/IBMPlexSerif.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
5
- @font-face { font-family: "IBM Plex Mono"; src: url("/fonts/IBMPlexMono.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
7
+ @font-face { font-family: "IBM Plex Mono"; src: url("/fonts/IBMPlexMono.woff2") format("woff2"); font-weight: 400; font-display: swap; }
8
+
9
+ /* ---------------------------------------------------------------- tokens */
6
10
 
7
11
  :root {
8
- --mode: var(--gl-accent);
9
- --mode-deep: var(--gl-accent-deep);
10
- --on-mode: var(--gl-on-accent);
11
- --add: #1d7a3a;
12
- --rem: #b3261e;
13
- --warn: #8a5a00;
12
+ --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
13
+ --serif: "IBM Plex Serif", Georgia, serif;
14
+ --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
15
+
16
+ --bg: #f7f6f2;
17
+ --surface: #efede7;
18
+ --raised: #ffffff;
19
+ --text: #1c1b19;
20
+ --muted: #5f5c55;
21
+ --faint: #8a867d;
22
+ --rule: #e0ddd4;
23
+ --rule-strong: #c8c3b8;
24
+ --shadow: 0 1px 2px rgb(28 27 25 / 0.05), 0 8px 24px -12px rgb(28 27 25 / 0.18);
25
+
26
+ --researcher: #1d4f7c;
27
+ --researcher-soft: #e3ebf3;
28
+ --librarian: #a33b14;
29
+ --librarian-soft: #f5e6de;
30
+ --on-accent: #ffffff;
31
+
32
+ --add: #256b3b;
33
+ --add-soft: #e2f0e5;
34
+ --rem: #a8321d;
35
+ --rem-soft: #f7e3de;
36
+ --warn: #946412;
37
+
38
+ --radius: 6px;
39
+ --radius-lg: 10px;
14
40
  --side-w: 17rem;
41
+ --measure: 46rem;
15
42
  }
43
+
16
44
  @media (prefers-color-scheme: dark) {
17
45
  :root:not([data-theme="light"]) {
18
- --gl-bg: #10161c;
19
- --gl-surface: #171f26;
20
- --gl-surface-raised: #1f2932;
21
- --gl-text: #e8eef2;
22
- --gl-text-muted: #9aa4ab;
23
- --gl-border: #2a3540;
24
- --gl-accent: #3d97ff;
25
- --gl-accent-bright: #6cb2ff;
26
- --gl-accent-deep: #007aff;
27
- --gl-on-accent: #0b1218;
28
- --gl-tint-pale: #93b7c9;
29
- --add: #8fcf9a;
30
- --rem: #f0a39c;
31
- --warn: #e3b35c;
46
+ --bg: #141413;
47
+ --surface: #1c1c1a;
48
+ --raised: #232320;
49
+ --text: #ebe8e1;
50
+ --muted: #a7a399;
51
+ --faint: #7b776f;
52
+ --rule: #2e2d2a;
53
+ --rule-strong: #45433e;
54
+ --shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 12px 32px -12px rgb(0 0 0 / 0.6);
55
+ --researcher: #7fb0de;
56
+ --researcher-soft: #1b2733;
57
+ --librarian: #e48a5f;
58
+ --librarian-soft: #33221a;
59
+ --on-accent: #141413;
60
+ --add: #7cc493;
61
+ --add-soft: #1a2c20;
62
+ --rem: #ec8a70;
63
+ --rem-soft: #36201b;
64
+ --warn: #d6a84e;
32
65
  }
33
66
  }
34
- [data-theme="dark"], html[data-theme="dark"] {
35
- --gl-bg: #10161c;
36
- --gl-surface: #171f26;
37
- --gl-surface-raised: #1f2932;
38
- --gl-text: #e8eef2;
39
- --gl-text-muted: #9aa4ab;
40
- --gl-border: #2a3540;
41
- --gl-accent: #3d97ff;
42
- --gl-accent-bright: #6cb2ff;
43
- --gl-accent-deep: #007aff;
44
- --gl-on-accent: #0b1218;
45
- --gl-tint-pale: #93b7c9;
46
- --add: #8fcf9a;
47
- --rem: #f0a39c;
48
- --warn: #e3b35c;
49
- }
50
- body[data-mode="librarian"] { --mode: #a8520f; --mode-deep: #7f3d09; --on-mode: #fff8f0; }
51
- @media (prefers-color-scheme: dark) {
52
- :root:not([data-theme="light"]) body[data-mode="librarian"] { --mode: #e0832a; --mode-deep: #f09a48; --on-mode: #140c04; }
53
- }
54
- [data-theme="dark"] body[data-mode="librarian"], html[data-theme="dark"] body[data-mode="librarian"] {
55
- --mode: #e0832a; --mode-deep: #f09a48; --on-mode: #140c04;
67
+
68
+ :root[data-theme="dark"] {
69
+ --bg: #141413;
70
+ --surface: #1c1c1a;
71
+ --raised: #232320;
72
+ --text: #ebe8e1;
73
+ --muted: #a7a399;
74
+ --faint: #7b776f;
75
+ --rule: #2e2d2a;
76
+ --rule-strong: #45433e;
77
+ --shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 12px 32px -12px rgb(0 0 0 / 0.6);
78
+ --researcher: #7fb0de;
79
+ --researcher-soft: #1b2733;
80
+ --librarian: #e48a5f;
81
+ --librarian-soft: #33221a;
82
+ --on-accent: #141413;
83
+ --add: #7cc493;
84
+ --add-soft: #1a2c20;
85
+ --rem: #ec8a70;
86
+ --rem-soft: #36201b;
87
+ --warn: #d6a84e;
56
88
  }
57
89
 
90
+ /* The mode sets the accent: blue for the researcher, rust for the librarian. */
91
+ body { --accent: var(--researcher); --accent-soft: var(--researcher-soft); }
92
+ body[data-mode="librarian"] { --accent: var(--librarian); --accent-soft: var(--librarian-soft); }
93
+
94
+ /* ---------------------------------------------------------------- base */
95
+
58
96
  *, *::before, *::after { box-sizing: border-box; }
59
97
  html, body { height: 100%; }
98
+
60
99
  body {
61
- margin: 0; background: var(--gl-bg); color: var(--gl-text);
62
- font-family: var(--gl-font-sans); font-size: 1rem; line-height: 1.55;
63
- transition: background-color 0.2s ease, color 0.2s ease;
100
+ margin: 0;
101
+ background: var(--bg);
102
+ color: var(--text);
103
+ font-family: var(--sans);
104
+ font-size: 15px;
105
+ line-height: 1.5;
106
+ -webkit-font-smoothing: antialiased;
107
+ -moz-osx-font-smoothing: grayscale;
108
+ text-rendering: optimizeLegibility;
64
109
  }
110
+
65
111
  button, input, select, textarea { font: inherit; color: inherit; }
66
- a { color: var(--gl-accent); }
112
+ a { color: var(--accent); text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
113
+ a:hover { text-decoration-thickness: 2px; }
114
+ svg { flex: none; }
115
+
67
116
  .visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
68
117
  [hidden] { display: none !important; }
69
- :focus-visible { outline: 2px solid var(--mode); outline-offset: 2px; }
70
-
71
- /* ---- buttons */
72
- button { cursor: pointer; border-radius: var(--gl-radius-md); border: 1px solid transparent; padding: 0.45rem 0.9rem; background: none; }
73
- button:disabled { opacity: 0.5; cursor: default; }
74
- .primary { background: var(--mode); color: var(--on-mode); font-weight: 600; }
75
- .primary:hover:not(:disabled) { background: var(--mode-deep); }
76
- .secondary { border-color: var(--gl-border); background: var(--gl-surface-raised); }
77
- .secondary:hover:not(:disabled) { border-color: var(--mode); }
78
- .ghost { color: var(--gl-text-muted); }
79
- .ghost:hover { color: var(--gl-text); background: var(--gl-surface); }
118
+ :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
119
+ ::selection { background: var(--accent-soft); }
120
+
121
+ /* Icons drawn with strokes, at the size of the text. */
122
+ .icon-btn svg, .new-btn svg, .brand .mark, .icon {
123
+ width: 18px;
124
+ height: 18px;
125
+ fill: none;
126
+ stroke: currentColor;
127
+ stroke-width: 1.6;
128
+ stroke-linecap: round;
129
+ stroke-linejoin: round;
130
+ }
131
+
132
+ /* ---------------------------------------------------------------- buttons */
133
+
134
+ button { cursor: pointer; background: none; border: 1px solid transparent; border-radius: var(--radius); padding: 0.4rem 0.85rem; line-height: 1.3; }
135
+ button:disabled { opacity: 0.45; cursor: default; }
136
+
137
+ .primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 550; }
138
+ .primary:hover:not(:disabled) { filter: brightness(1.08); }
139
+ .secondary { background: var(--raised); border-color: var(--rule-strong); }
140
+ .secondary:hover:not(:disabled) { border-color: var(--text); }
141
+ .ghost { color: var(--muted); }
142
+ .ghost:hover { color: var(--text); background: var(--surface); }
143
+ .link-btn { padding: 0.1rem 0.2rem; color: var(--muted); font-size: 0.82rem; }
144
+ .link-btn:hover { color: var(--text); text-decoration: underline; text-underline-offset: 0.18em; }
80
145
  .small { font-size: 0.85rem; }
81
- .muted { color: var(--gl-text-muted); }
82
- .block { width: 100%; }
146
+ .primary.small, .secondary.small { padding: 0.25rem 0.6rem; }
147
+ .muted { color: var(--muted); }
148
+
149
+ .icon-btn {
150
+ display: inline-grid;
151
+ place-items: center;
152
+ width: 34px;
153
+ height: 34px;
154
+ padding: 0;
155
+ color: var(--muted);
156
+ border-radius: var(--radius);
157
+ }
158
+ .icon-btn:hover { color: var(--text); background: var(--surface); }
159
+ .icon-btn[aria-pressed="true"] { color: var(--accent); background: var(--accent-soft); }
160
+
161
+ .chip-btn {
162
+ max-width: 16rem;
163
+ overflow: hidden;
164
+ text-overflow: ellipsis;
165
+ white-space: nowrap;
166
+ font-family: var(--mono);
167
+ font-size: 0.78rem;
168
+ color: var(--muted);
169
+ border-color: var(--rule);
170
+ background: var(--raised);
171
+ padding: 0.35rem 0.65rem;
172
+ }
173
+ .chip-btn:hover { color: var(--text); border-color: var(--rule-strong); }
174
+
175
+ select {
176
+ appearance: none;
177
+ border: 1px solid var(--rule);
178
+ border-radius: var(--radius);
179
+ background: var(--raised) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' fill='none' stroke='%23888' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 0.5rem center / 12px;
180
+ padding: 0.35rem 1.8rem 0.35rem 0.65rem;
181
+ font-size: 0.85rem;
182
+ cursor: pointer;
183
+ }
184
+ select:hover { border-color: var(--rule-strong); }
185
+
186
+ /* ---------------------------------------------------------------- layout */
187
+
188
+ .app {
189
+ display: grid;
190
+ grid-template-columns: var(--side-w) minmax(0, 1fr);
191
+ grid-template-rows: auto minmax(0, 1fr);
192
+ height: 100vh;
193
+ height: 100dvh;
194
+ }
195
+ .app.side-collapsed { grid-template-columns: 0 minmax(0, 1fr); }
196
+ .app.side-collapsed .side { display: none; }
197
+
198
+ /* ---------------------------------------------------------------- top bar */
83
199
 
84
- /* ---- layout */
85
- .app { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); height: 100vh; height: 100dvh; }
86
200
  .top {
87
- grid-column: 1 / -1; display: flex; align-items: center; gap: 0.75rem 1.25rem; flex-wrap: wrap;
88
- padding: 0.6rem 1rem; border-bottom: 1px solid var(--gl-border); background: var(--gl-surface);
89
- }
90
- .brand { font-family: var(--gl-font-serif); font-weight: 600; font-size: 1.15rem; display: flex; align-items: center; gap: 0.45rem; }
91
- .mark { font-family: var(--gl-font-mono); font-size: 0.75rem; font-weight: 600; background: #12161b; color: #e0832a; padding: 0.15rem 0.35rem; border-radius: var(--gl-radius-md); }
92
- .menu-btn { display: none; }
93
- .modes { display: inline-flex; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-pill); padding: 2px; background: var(--gl-bg); }
94
- .modes button { border-radius: var(--gl-radius-pill); padding: 0.3rem 0.9rem; color: var(--gl-text-muted); }
95
- .modes button[aria-pressed="true"] { background: var(--mode); color: var(--on-mode); font-weight: 600; }
96
- .status { margin-left: auto; display: flex; align-items: center; gap: 0.5rem 0.9rem; flex-wrap: wrap; font-size: 0.88rem; }
97
- .library { display: inline-flex; align-items: center; gap: 0.45rem; color: var(--gl-text-muted); }
98
- .library-dot { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--gl-border); flex: none; transition: background 0.2s ease, box-shadow 0.2s ease; }
99
- .library.reachable .library-dot { background: var(--add); box-shadow: 0 0 6px var(--add); }
100
- .library.down .library-dot { background: var(--rem); box-shadow: 0 0 6px var(--rem); }
101
- .library.down { color: var(--rem); font-weight: 600; }
201
+ grid-column: 1 / -1;
202
+ display: flex;
203
+ align-items: center;
204
+ gap: 0.5rem 1rem;
205
+ padding: 0.55rem 1rem;
206
+ border-top: 3px solid var(--accent);
207
+ border-bottom: 1px solid var(--rule);
208
+ background: var(--bg);
209
+ }
210
+
211
+ .brand {
212
+ display: flex;
213
+ align-items: center;
214
+ gap: 0.45rem;
215
+ font-weight: 600;
216
+ font-size: 1.02rem;
217
+ letter-spacing: -0.01em;
218
+ margin-right: 0.25rem;
219
+ }
220
+ .brand .mark { color: var(--accent); }
221
+ .brand .hyphen { color: var(--accent); }
222
+
223
+ .modes {
224
+ display: inline-flex;
225
+ padding: 3px;
226
+ border-radius: 8px;
227
+ background: var(--surface);
228
+ border: 1px solid var(--rule);
229
+ }
230
+ .modes button {
231
+ padding: 0.28rem 0.8rem;
232
+ border-radius: 5px;
233
+ font-size: 0.86rem;
234
+ color: var(--muted);
235
+ border: 0;
236
+ }
237
+ .modes button:hover { color: var(--text); }
238
+ .modes button[aria-pressed="true"] {
239
+ background: var(--raised);
240
+ color: var(--accent);
241
+ font-weight: 600;
242
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.08), 0 0 0 1px var(--rule);
243
+ }
244
+
245
+ .status {
246
+ margin-left: auto;
247
+ display: flex;
248
+ align-items: center;
249
+ gap: 0.5rem;
250
+ min-width: 0;
251
+ }
252
+
253
+ .library {
254
+ display: inline-flex;
255
+ align-items: center;
256
+ gap: 0.45rem;
257
+ padding: 0.3rem 0.7rem;
258
+ border-radius: 999px;
259
+ font-size: 0.8rem;
260
+ color: var(--muted);
261
+ white-space: nowrap;
262
+ overflow: hidden;
263
+ text-overflow: ellipsis;
264
+ min-width: 0;
265
+ font-variant-numeric: tabular-nums;
266
+ }
267
+ .library-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--rule-strong); flex: none; }
268
+ .library.reachable .library-dot { background: var(--add); box-shadow: 0 0 0 3px var(--add-soft); }
269
+ .library.down { color: var(--rem); background: var(--rem-soft); font-weight: 550; }
270
+ .library.down .library-dot { background: var(--rem); }
102
271
  .library.checking .library-dot { background: var(--warn); animation: pulse 1.2s ease-in-out infinite; }
103
- .status select { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-surface-raised); padding: 0.3rem 0.5rem; }
104
- .model-btn, .theme-btn { font-family: var(--gl-font-mono); font-size: 0.8rem; border: 1px solid var(--gl-border); }
105
- .theme-btn { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.6rem; }
106
-
107
- .side { border-right: 1px solid var(--gl-border); background: var(--gl-surface); padding: 1rem; display: flex; flex-direction: column; gap: 1.25rem; overflow-y: auto; }
108
- .side h2 { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--gl-text-muted); margin: 0 0 0.5rem; font-weight: 600; }
109
- .side .grow { flex: 1; display: flex; flex-direction: column; min-height: 0; }
110
- .side-subhead { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.4rem; }
111
- .side-subhead h2 { margin: 0; }
112
- .search-wrap { margin-bottom: 0.6rem; }
113
- .search-wrap input { width: 100%; font-size: 0.8rem; padding: 0.35rem 0.55rem; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-surface-raised); color: var(--gl-text); }
114
- .search-wrap input:focus { outline: none; border-color: var(--mode); }
115
- .actions { display: flex; flex-direction: column; gap: 0.25rem; }
116
- .actions button { text-align: left; padding: 0.35rem 0.6rem; border-radius: var(--gl-radius-md); }
117
- .actions button:hover { background: var(--gl-bg); }
118
- .actions hr { border: 0; border-top: 1px solid var(--gl-border); margin: 0.35rem 0; width: 100%; }
119
- .sessions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.15rem; overflow-y: auto; flex: 1; }
120
- .sessions button { width: 100%; text-align: left; padding: 0.4rem 0.6rem; display: block; border-radius: var(--gl-radius-md); }
121
- .sessions button:hover { background: var(--gl-bg); }
122
- .sessions .current button { background: var(--gl-bg); border-color: var(--gl-border); }
123
- .sessions .when { display: flex; justify-content: space-between; font-size: 0.75rem; color: var(--gl-text-muted); margin-top: 0.15rem; }
124
- .sessions .badge { font-family: var(--gl-font-mono); font-size: 0.7rem; background: var(--gl-surface-raised); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-sm); padding: 0 0.3rem; }
125
- .sessions .what { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: 0.88rem; }
126
- .side-foot { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
127
- .version { font-size: 0.75rem; color: var(--gl-text-muted); font-family: var(--gl-font-mono); }
128
-
129
- /* ---- conversation */
130
- .chat { display: flex; flex-direction: column; min-height: 0; }
131
- .banner { margin: 0.75rem 1rem 0; padding: 0.6rem 0.9rem; border: 1px solid var(--gl-border); border-left: 3px solid var(--warn); border-radius: var(--gl-radius-md); background: var(--gl-surface); display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
132
- .log { flex: 1; overflow-y: auto; padding: 1.25rem 1rem 2rem; }
133
- .log > * { max-width: 48rem; margin-left: auto; margin-right: auto; }
134
- .msg { margin-top: 1.1rem; }
272
+
273
+ /* ---------------------------------------------------------------- side panel */
274
+
275
+ .side {
276
+ border-right: 1px solid var(--rule);
277
+ background: var(--surface);
278
+ padding: 0.9rem 0.75rem 0.75rem;
279
+ display: flex;
280
+ flex-direction: column;
281
+ gap: 1.1rem;
282
+ overflow-y: auto;
283
+ min-height: 0;
284
+ }
285
+
286
+ .side h2 {
287
+ font-size: 0.7rem;
288
+ font-weight: 600;
289
+ letter-spacing: 0.08em;
290
+ text-transform: uppercase;
291
+ color: var(--faint);
292
+ margin: 0 0 0.35rem;
293
+ padding: 0 0.5rem;
294
+ }
295
+
296
+ .new-btn {
297
+ display: flex;
298
+ align-items: center;
299
+ gap: 0.5rem;
300
+ width: 100%;
301
+ padding: 0.5rem 0.7rem;
302
+ background: var(--raised);
303
+ border: 1px solid var(--rule);
304
+ font-weight: 550;
305
+ box-shadow: 0 1px 1px rgb(0 0 0 / 0.03);
306
+ }
307
+ .new-btn:hover { border-color: var(--rule-strong); }
308
+ .new-btn svg { width: 16px; height: 16px; color: var(--accent); }
309
+
310
+ .actions { display: flex; flex-direction: column; }
311
+ .actions button {
312
+ text-align: left;
313
+ padding: 0.32rem 0.5rem;
314
+ font-size: 0.88rem;
315
+ color: var(--text);
316
+ border-radius: 5px;
317
+ }
318
+ .actions button:hover { background: var(--bg); }
319
+ .actions hr { border: 0; border-top: 1px solid var(--rule); margin: 0.4rem 0.5rem; }
320
+
321
+ .side .grow { flex: 1; display: flex; flex-direction: column; min-height: 8rem; }
322
+ .side-subhead { display: flex; justify-content: space-between; align-items: baseline; padding-right: 0.3rem; }
323
+
324
+ .search {
325
+ width: 100%;
326
+ margin: 0.15rem 0 0.4rem;
327
+ font-size: 0.84rem;
328
+ padding: 0.38rem 0.6rem;
329
+ border: 1px solid var(--rule);
330
+ border-radius: var(--radius);
331
+ background: var(--raised);
332
+ }
333
+ .search:focus { outline: none; border-color: var(--accent); }
334
+
335
+ .sessions { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; }
336
+ .sessions > li.muted { padding: 0.3rem 0.5rem; }
337
+ .sessions button {
338
+ width: 100%;
339
+ text-align: left;
340
+ padding: 0.42rem 0.5rem;
341
+ display: block;
342
+ border-radius: 5px;
343
+ }
344
+ .sessions button:hover { background: var(--bg); }
345
+ .sessions .current button { background: var(--raised); box-shadow: inset 2px 0 0 var(--accent), 0 0 0 1px var(--rule); }
346
+ .sessions .what {
347
+ display: -webkit-box;
348
+ -webkit-line-clamp: 2;
349
+ -webkit-box-orient: vertical;
350
+ overflow: hidden;
351
+ font-size: 0.86rem;
352
+ line-height: 1.35;
353
+ }
354
+ .sessions .when {
355
+ display: flex;
356
+ justify-content: space-between;
357
+ font-size: 0.72rem;
358
+ color: var(--faint);
359
+ margin-top: 0.15rem;
360
+ font-variant-numeric: tabular-nums;
361
+ }
362
+ .sessions .badge { font-family: var(--mono); font-size: 0.68rem; }
363
+
364
+ .side-foot {
365
+ display: grid;
366
+ gap: 0.55rem;
367
+ border-top: 1px solid var(--rule);
368
+ padding: 0.7rem 0.5rem 0;
369
+ }
370
+ .side-foot-row { display: flex; justify-content: space-between; align-items: center; }
371
+ .version { font-family: var(--mono); font-size: 0.7rem; color: var(--faint); }
372
+
373
+ /* A switch built on a checkbox. */
374
+ .switch { display: flex; align-items: center; gap: 0.55rem; font-size: 0.84rem; cursor: pointer; line-height: 1.3; }
375
+ .switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
376
+ .switch .track {
377
+ position: relative;
378
+ flex: none;
379
+ width: 28px;
380
+ height: 16px;
381
+ border-radius: 999px;
382
+ background: var(--rule-strong);
383
+ transition: background-color 0.15s ease;
384
+ }
385
+ .switch .track::after {
386
+ content: "";
387
+ position: absolute;
388
+ top: 2px;
389
+ left: 2px;
390
+ width: 12px;
391
+ height: 12px;
392
+ border-radius: 50%;
393
+ background: #fff;
394
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
395
+ transition: transform 0.15s ease;
396
+ }
397
+ .switch input:checked + .track { background: var(--accent); }
398
+ .switch input:checked + .track::after { transform: translateX(12px); }
399
+ .switch input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }
400
+ .switch input:disabled + .track { opacity: 0.5; }
401
+
402
+ /* ---------------------------------------------------------------- conversation */
403
+
404
+ .chat { display: flex; flex-direction: column; min-height: 0; background: var(--bg); }
405
+
406
+ body.layout-full { --measure: 72rem; }
407
+
408
+ .banner {
409
+ width: min(calc(100% - 2.5rem), var(--measure));
410
+ margin: 0.9rem auto 0;
411
+ padding: 0.6rem 0.6rem 0.6rem 0.9rem;
412
+ border: 1px solid var(--rule);
413
+ border-left: 3px solid var(--warn);
414
+ border-radius: var(--radius);
415
+ background: var(--raised);
416
+ display: flex;
417
+ gap: 0.75rem;
418
+ align-items: center;
419
+ justify-content: space-between;
420
+ font-size: 0.9rem;
421
+ }
422
+
423
+ .log {
424
+ flex: 1;
425
+ overflow-y: auto;
426
+ padding: 1.75rem 1.25rem 2rem;
427
+ scrollbar-gutter: stable;
428
+ }
429
+ .log > * { width: min(100%, var(--measure)); margin-inline: auto; }
430
+
431
+ .msg { margin-top: 1.6rem; }
432
+ .msg:first-child { margin-top: 0; }
433
+
135
434
  .msg.user { display: flex; justify-content: flex-end; }
136
- .msg.user .bubble { background: var(--gl-surface-raised); border: 1px solid var(--gl-border); border-radius: 12px 12px 3px 12px; padding: 0.55rem 0.9rem; max-width: 85%; white-space: pre-wrap; overflow-wrap: anywhere; }
137
- .msg.assistant .md { overflow-wrap: anywhere; }
435
+ .msg.user .bubble {
436
+ background: var(--raised);
437
+ border: 1px solid var(--rule);
438
+ border-radius: var(--radius-lg) var(--radius-lg) 3px var(--radius-lg);
439
+ padding: 0.6rem 0.95rem;
440
+ max-width: min(36rem, 88%);
441
+ white-space: pre-wrap;
442
+ overflow-wrap: anywhere;
443
+ font-size: 0.95rem;
444
+ }
445
+ .msg.user details.bubble summary { cursor: pointer; color: var(--muted); }
446
+ .msg.user details.bubble[open] summary { margin-bottom: 0.4rem; }
447
+
448
+ /* Replies read as text, in the serif. */
449
+ .md {
450
+ font-family: var(--serif);
451
+ font-size: 1.02rem;
452
+ line-height: 1.68;
453
+ overflow-wrap: anywhere;
454
+ }
138
455
  .md > :first-child { margin-top: 0; }
139
456
  .md > :last-child { margin-bottom: 0; }
140
- .md p, .md ul, .md ol { margin: 0.6rem 0; }
141
- .md h1, .md h2, .md h3 { font-family: var(--gl-font-serif); line-height: 1.25; margin: 1.1rem 0 0.4rem; }
142
- .md h1 { font-size: 1.35rem; } .md h2 { font-size: 1.2rem; } .md h3 { font-size: 1.05rem; }
143
- .md code { font-family: var(--gl-font-mono); font-size: 0.86em; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-sm); padding: 0.05em 0.3em; }
144
- .md pre { background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.75rem; overflow-x: auto; font-size: 0.85rem; }
145
- .md pre code { background: none; border: 0; padding: 0; }
146
- .pre-wrap { position: relative; margin: 0.6rem 0; }
147
- .pre-wrap pre { margin: 0; }
457
+ .md p, .md ul, .md ol { margin: 0.7rem 0; }
458
+ .md li { margin: 0.2rem 0; }
459
+ .md li::marker { color: var(--faint); }
460
+ .md h1, .md h2, .md h3, .md h4 {
461
+ font-family: var(--sans);
462
+ line-height: 1.3;
463
+ letter-spacing: -0.01em;
464
+ margin: 1.6rem 0 0.5rem;
465
+ font-weight: 600;
466
+ }
467
+ .md h1 { font-size: 1.3rem; }
468
+ .md h2 { font-size: 1.12rem; }
469
+ .md h3 { font-size: 1rem; }
470
+ .md h4 { font-size: 0.92rem; color: var(--muted); }
471
+ .md strong { font-weight: 600; }
472
+ .md hr { border: 0; border-top: 1px solid var(--rule); margin: 1.5rem 0; }
473
+ .msg.assistant + .msg.assistant { margin-top: 0.9rem; }
474
+ .msg.assistant .md + .md { margin-top: 0.9rem; }
475
+
476
+ .md blockquote {
477
+ margin: 1rem 0;
478
+ padding: 0.1rem 0 0.1rem 1rem;
479
+ border-left: 2px solid var(--accent);
480
+ color: var(--muted);
481
+ }
482
+
483
+ .md code {
484
+ font-family: var(--mono);
485
+ font-size: 0.84em;
486
+ background: var(--surface);
487
+ border: 1px solid var(--rule);
488
+ border-radius: 4px;
489
+ padding: 0.05em 0.32em;
490
+ }
491
+
492
+ .md pre {
493
+ margin: 0;
494
+ background: var(--surface);
495
+ border: 1px solid var(--rule);
496
+ border-radius: var(--radius);
497
+ padding: 0.85rem 1rem;
498
+ overflow-x: auto;
499
+ font-family: var(--mono);
500
+ font-size: 0.8rem;
501
+ line-height: 1.55;
502
+ }
503
+ .md pre code { background: none; border: 0; padding: 0; font-size: inherit; }
504
+
505
+ .pre-wrap { position: relative; margin: 0.9rem 0; }
148
506
  .copy-btn {
149
- position: absolute; top: 0.4rem; right: 0.4rem;
150
- font-family: var(--gl-font-mono); font-size: 0.72rem;
151
- background: var(--gl-surface-raised); border: 1px solid var(--gl-border);
152
- border-radius: var(--gl-radius-sm); padding: 0.15rem 0.5rem;
153
- color: var(--gl-text-muted); cursor: pointer; opacity: 0;
154
- transition: opacity 0.15s ease, color 0.15s ease, border-color 0.15s ease;
155
- z-index: 2;
507
+ position: absolute;
508
+ top: 0.4rem;
509
+ right: 0.4rem;
510
+ font-family: var(--sans);
511
+ font-size: 0.74rem;
512
+ background: var(--raised);
513
+ border: 1px solid var(--rule);
514
+ padding: 0.15rem 0.5rem;
515
+ color: var(--muted);
516
+ opacity: 0;
517
+ transition: opacity 0.12s ease;
156
518
  }
157
519
  .pre-wrap:hover .copy-btn, .copy-btn:focus-visible { opacity: 1; }
158
- .copy-btn:hover { color: var(--gl-text); border-color: var(--mode); }
520
+ .copy-btn:hover { color: var(--text); border-color: var(--rule-strong); }
159
521
  .copy-btn.copied { opacity: 1; color: var(--add); border-color: var(--add); }
160
522
 
161
- .msg-actions { display: flex; gap: 0.4rem; margin-top: 0.45rem; opacity: 0; transition: opacity 0.15s ease; }
523
+ /* Tables: citekeys, screening logs, evidence. */
524
+ .md-table-wrap {
525
+ overflow-x: auto;
526
+ margin: 1.1rem 0;
527
+ border: 1px solid var(--rule);
528
+ border-radius: var(--radius);
529
+ background: var(--raised);
530
+ }
531
+ .md table {
532
+ border-collapse: collapse;
533
+ width: 100%;
534
+ font-family: var(--sans);
535
+ font-size: 0.86rem;
536
+ line-height: 1.45;
537
+ font-variant-numeric: tabular-nums;
538
+ }
539
+ .md th, .md td { padding: 0.5rem 0.75rem; text-align: left; vertical-align: top; border-bottom: 1px solid var(--rule); }
540
+ .md tr:last-child td { border-bottom: 0; }
541
+ .md th {
542
+ font-size: 0.72rem;
543
+ font-weight: 600;
544
+ letter-spacing: 0.04em;
545
+ text-transform: uppercase;
546
+ color: var(--muted);
547
+ white-space: nowrap;
548
+ background: var(--surface);
549
+ }
550
+ .md td:first-child { white-space: nowrap; }
551
+ .md td code { white-space: nowrap; }
552
+ .md tbody tr:hover td { background: var(--bg); }
553
+
554
+ .msg-actions { display: flex; gap: 0.25rem; margin-top: 0.4rem; opacity: 0; transition: opacity 0.12s ease; }
162
555
  .msg.assistant:hover .msg-actions, .msg-actions:focus-within { opacity: 1; }
163
- .msg-action-btn { font-size: 0.75rem; padding: 0.15rem 0.5rem; border-radius: var(--gl-radius-sm); color: var(--gl-text-muted); border: 1px solid transparent; background: none; }
164
- .msg-action-btn:hover { color: var(--gl-text); background: var(--gl-surface-raised); border-color: var(--gl-border); }
165
- .msg-action-btn.copied { color: var(--add); border-color: var(--add); }
166
-
167
- .md blockquote { margin: 0.6rem 0; padding-left: 0.9rem; border-left: 3px solid var(--gl-tint-pale); color: var(--gl-text-muted); }
168
- .md table { border-collapse: collapse; display: block; overflow-x: auto; font-size: 0.9rem; }
169
- .md th, .md td { border-bottom: 1px solid var(--gl-border); padding: 0.3rem 0.6rem; text-align: left; vertical-align: top; }
170
- .md th { font-size: 0.82rem; color: var(--gl-text-muted); }
171
- .tool { margin-top: 0.5rem; font-size: 0.86rem; color: var(--gl-text-muted); }
172
- .tool summary { cursor: pointer; list-style: none; display: flex; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
556
+ .msg-action-btn { font-size: 0.75rem; padding: 0.15rem 0.45rem; color: var(--faint); }
557
+ .msg-action-btn:hover { color: var(--text); background: var(--surface); }
558
+ .msg-action-btn.copied { color: var(--add); }
559
+
560
+ /* Tool calls: one quiet line each; the result opens below. */
561
+ .tool { margin: 0.35rem 0; font-size: 0.82rem; color: var(--muted); }
562
+ .msg.assistant > .tool:first-child { margin-top: 0; }
563
+ .tool + .md, .md + .tool { margin-top: 0.8rem; }
564
+ .tool summary {
565
+ cursor: pointer;
566
+ list-style: none;
567
+ display: flex;
568
+ gap: 0.55rem;
569
+ align-items: baseline;
570
+ padding: 0.28rem 0.55rem;
571
+ margin-left: -0.55rem;
572
+ border-radius: 5px;
573
+ width: fit-content;
574
+ max-width: calc(100% + 0.55rem);
575
+ }
576
+ .tool summary:hover { background: var(--surface); }
173
577
  .tool summary::-webkit-details-marker { display: none; }
174
- .tool summary::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--gl-border); flex: none; align-self: center; }
175
- .tool.running summary::before { background: var(--mode); animation: pulse 1.2s ease-in-out infinite; }
578
+ .tool summary::before {
579
+ content: "";
580
+ width: 6px;
581
+ height: 6px;
582
+ border-radius: 50%;
583
+ background: var(--rule-strong);
584
+ flex: none;
585
+ align-self: center;
586
+ }
587
+ .tool .label { color: var(--text); white-space: nowrap; }
588
+ .tool.running summary::before { background: var(--accent); animation: pulse 1.1s ease-in-out infinite; }
176
589
  .tool.done summary::before { background: var(--add); }
177
590
  .tool.error summary::before { background: var(--rem); }
178
- .tool .args { font-family: var(--gl-font-mono); font-size: 0.78rem; overflow-wrap: anywhere; }
179
- .tool pre { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.78rem; max-height: 18rem; overflow-y: auto; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.6rem; color: var(--gl-text); }
180
- .tool .open { margin-left: 0.25rem; padding: 0.1rem 0.5rem; border: 1px solid var(--gl-border); font-size: 0.78rem; }
181
- .note { margin-top: 1rem; padding: 0.6rem 0.9rem; border-radius: var(--gl-radius-md); background: var(--gl-surface); border: 1px solid var(--gl-border); font-size: 0.9rem; white-space: pre-wrap; overflow-wrap: anywhere; }
591
+ .tool.error .label { color: var(--rem); }
592
+ .tool .args { font-family: var(--mono); font-size: 0.74rem; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
593
+ .tool[open] .args { white-space: normal; overflow-wrap: anywhere; }
594
+ .tool pre {
595
+ margin: 0.35rem 0 0.6rem 0.6rem;
596
+ white-space: pre-wrap;
597
+ overflow-wrap: anywhere;
598
+ font-family: var(--mono);
599
+ font-size: 0.75rem;
600
+ line-height: 1.5;
601
+ max-height: 18rem;
602
+ overflow-y: auto;
603
+ background: var(--surface);
604
+ border: 1px solid var(--rule);
605
+ border-radius: var(--radius);
606
+ padding: 0.65rem 0.8rem;
607
+ color: var(--text);
608
+ }
609
+ .tool .open {
610
+ font-size: 0.74rem;
611
+ padding: 0.05rem 0.45rem;
612
+ border: 1px solid var(--rule-strong);
613
+ background: var(--raised);
614
+ color: var(--text);
615
+ }
616
+
617
+ .note {
618
+ margin-top: 1rem;
619
+ padding: 0.6rem 0.9rem;
620
+ border-radius: var(--radius);
621
+ background: var(--surface);
622
+ border: 1px solid var(--rule);
623
+ font-size: 0.88rem;
624
+ white-space: pre-wrap;
625
+ overflow-wrap: anywhere;
626
+ }
182
627
  .note.warning { border-left: 3px solid var(--warn); }
183
628
  .note.error { border-left: 3px solid var(--rem); }
184
- .note.mono { font-family: var(--gl-font-mono); font-size: 0.82rem; }
185
- .working { margin-top: 0.75rem; color: var(--gl-text-muted); font-size: 0.88rem; display: flex; gap: 0.5rem; align-items: center; }
186
- .working::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--mode); animation: pulse 1.2s ease-in-out infinite; }
629
+ .note.mono { font-family: var(--mono); font-size: 0.76rem; line-height: 1.55; }
630
+ .note pre { font-family: var(--mono); font-size: 0.74rem; white-space: pre-wrap; }
631
+ .note button { margin-top: 0.5rem; }
632
+
633
+ .working {
634
+ margin-top: 1rem;
635
+ color: var(--muted);
636
+ font-size: 0.85rem;
637
+ display: flex;
638
+ gap: 0.55rem;
639
+ align-items: center;
640
+ }
641
+ .working::before {
642
+ content: "";
643
+ width: 28px;
644
+ height: 3px;
645
+ border-radius: 2px;
646
+ background: linear-gradient(90deg, var(--accent) 0 40%, var(--rule) 40% 100%);
647
+ background-size: 250% 100%;
648
+ animation: sweep 1.3s ease-in-out infinite alternate;
649
+ }
650
+ @keyframes sweep { from { background-position: 100% 0; } to { background-position: 0 0; } }
187
651
  @keyframes pulse { 50% { opacity: 0.3; } }
188
- @media (prefers-reduced-motion: reduce) { .working::before, .tool.running summary::before { animation: none; } }
189
652
 
190
- .empty { text-align: center; padding-top: 12vh; }
191
- .empty h1 { font-family: var(--gl-font-serif); font-weight: 600; font-size: 1.6rem; margin: 0 0 1rem; }
192
- .chips { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; }
193
- .chips button { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-pill); background: var(--gl-surface-raised); padding: 0.4rem 0.9rem; }
194
- .chips button:hover { border-color: var(--mode); }
653
+ /* Empty conversation. */
654
+ .empty { padding-top: 11vh; }
655
+ .empty .kicker {
656
+ font-size: 0.72rem;
657
+ font-weight: 600;
658
+ letter-spacing: 0.08em;
659
+ text-transform: uppercase;
660
+ color: var(--accent);
661
+ margin: 0 0 0.6rem;
662
+ }
663
+ .empty h1 {
664
+ font-family: var(--serif);
665
+ font-weight: 500;
666
+ font-size: clamp(1.6rem, 3.2vw, 2.15rem);
667
+ line-height: 1.2;
668
+ letter-spacing: -0.015em;
669
+ margin: 0 0 0.6rem;
670
+ }
671
+ .empty .lede { color: var(--muted); max-width: 34rem; margin: 0 0 1.75rem; }
672
+ .chips { display: grid; gap: 0.5rem; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); }
673
+ .chips button {
674
+ text-align: left;
675
+ border: 1px solid var(--rule);
676
+ border-radius: var(--radius-lg);
677
+ background: var(--raised);
678
+ padding: 0.75rem 0.9rem;
679
+ font-size: 0.9rem;
680
+ line-height: 1.4;
681
+ }
682
+ .chips button:hover { border-color: var(--accent); }
683
+
684
+ body > p.empty { text-align: center; color: var(--muted); padding: 30vh 1rem 0; margin: 0; }
195
685
 
196
- /* ---- composer */
197
- .composer { position: relative; display: flex; gap: 0.6rem; align-items: flex-end; padding: 0.75rem 1rem 1rem; border-top: 1px solid var(--gl-border); background: var(--gl-bg); }
686
+ /* ---------------------------------------------------------------- composer */
687
+
688
+ .composer { position: relative; padding: 0 1.25rem 1.1rem; }
689
+ .composer-box {
690
+ width: min(100%, var(--measure));
691
+ margin-inline: auto;
692
+ border: 1px solid var(--rule-strong);
693
+ border-radius: 12px;
694
+ background: var(--raised);
695
+ box-shadow: var(--shadow);
696
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
697
+ }
698
+ .composer-box:focus-within { border-color: var(--accent); box-shadow: var(--shadow), 0 0 0 3px var(--accent-soft); }
198
699
  .composer textarea {
199
- flex: 1; resize: none; max-height: 40vh; min-height: 2.8rem; padding: 0.6rem 0.8rem;
200
- border: 1px solid var(--gl-border); border-radius: var(--gl-radius-lg); background: var(--gl-surface-raised);
201
- }
202
- .composer textarea:focus { outline: none; border-color: var(--mode); box-shadow: 0 0 0 1px var(--mode); }
203
- .composer-buttons { display: flex; gap: 0.4rem; }
204
- .suggest { position: absolute; left: 1rem; right: 1rem; bottom: calc(100% - 0.25rem); max-width: 30rem; max-height: 16rem; overflow-y: auto; background: var(--gl-surface-raised); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); box-shadow: 0 8px 24px -12px rgba(0,0,0,0.35); padding: 0.25rem; }
205
- .suggest button { display: block; width: 100%; text-align: left; padding: 0.35rem 0.6rem; }
206
- .suggest button[aria-selected="true"], .suggest button:hover { background: var(--gl-bg); }
207
- .suggest .name { font-family: var(--gl-font-mono); font-size: 0.85rem; }
208
- .suggest .desc { color: var(--gl-text-muted); font-size: 0.8rem; margin-left: 0.5rem; }
209
-
210
- /* ---- dialogs */
211
- .modal { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-lg); background: var(--gl-surface-raised); color: var(--gl-text); padding: 1.25rem 1.4rem; width: min(40rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); overflow-y: auto; box-shadow: 0 24px 60px -20px rgba(0,0,0,0.5); }
212
- .modal.wide { width: min(46rem, calc(100vw - 2rem)); }
213
- .modal::backdrop { background: rgba(16, 22, 28, 0.55); backdrop-filter: blur(2px); }
214
- .modal h2 { font-family: var(--gl-font-serif); font-size: 1.25rem; margin: 0 0 0.25rem; }
215
- .modal h3 { font-size: 0.95rem; margin: 1.25rem 0 0.5rem; }
216
- .modal .hint { color: var(--gl-text-muted); margin: 0 0 0.75rem; font-size: 0.9rem; }
217
- .preview { font-family: var(--gl-font-mono); font-size: 0.82rem; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.75rem; max-height: 55vh; overflow-y: auto; margin: 0 0 1rem; }
218
- .preview .add { color: var(--add); background: rgba(29, 122, 58, 0.12); padding: 0.1em 0.35em; border-radius: var(--gl-radius-sm); font-weight: 600; }
219
- .preview .rem { color: var(--rem); background: rgba(179, 38, 30, 0.12); padding: 0.1em 0.35em; border-radius: var(--gl-radius-sm); font-weight: 600; }
220
- .modal-buttons { display: flex; justify-content: flex-end; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }
221
- .modal-shortcut-hint { font-size: 0.76rem; color: var(--gl-text-muted); font-family: var(--gl-font-mono); margin-right: auto; }
700
+ display: block;
701
+ width: 100%;
702
+ resize: none;
703
+ max-height: 40vh;
704
+ min-height: 3rem;
705
+ padding: 0.8rem 0.95rem 0.2rem;
706
+ border: 0;
707
+ background: transparent;
708
+ font-size: 0.98rem;
709
+ line-height: 1.5;
710
+ }
711
+ .composer textarea:focus { outline: none; }
712
+ .composer textarea::placeholder { color: var(--faint); }
713
+ .composer-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.35rem 0.5rem 0.5rem 0.95rem; }
714
+ .composer-hint { font-size: 0.74rem; color: var(--faint); }
715
+ .composer-buttons { display: flex; gap: 0.4rem; margin-left: auto; }
716
+ .composer-buttons button { padding: 0.38rem 0.95rem; font-size: 0.88rem; }
717
+
718
+ .suggest {
719
+ position: absolute;
720
+ left: max(1.25rem, calc((100% - var(--measure)) / 2));
721
+ bottom: calc(100% - 0.4rem);
722
+ width: min(32rem, calc(100% - 2.5rem));
723
+ max-height: 18rem;
724
+ overflow-y: auto;
725
+ background: var(--raised);
726
+ border: 1px solid var(--rule-strong);
727
+ border-radius: var(--radius-lg);
728
+ box-shadow: var(--shadow);
729
+ padding: 0.3rem;
730
+ z-index: 5;
731
+ }
732
+ .suggest button { display: flex; align-items: baseline; gap: 0.6rem; width: 100%; text-align: left; padding: 0.38rem 0.55rem; border-radius: 5px; }
733
+ .suggest button[aria-selected="true"], .suggest button:hover { background: var(--accent-soft); }
734
+ .suggest .name { font-family: var(--mono); font-size: 0.8rem; color: var(--accent); white-space: nowrap; }
735
+ .suggest .desc { color: var(--muted); font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
736
+
737
+ /* ---------------------------------------------------------------- dialogs */
738
+
739
+ .modal {
740
+ border: 1px solid var(--rule-strong);
741
+ border-radius: 12px;
742
+ background: var(--raised);
743
+ color: var(--text);
744
+ padding: 1.4rem 1.5rem 1.25rem;
745
+ width: min(40rem, calc(100vw - 2rem));
746
+ max-height: calc(100dvh - 2rem);
747
+ overflow-y: auto;
748
+ box-shadow: 0 24px 60px -16px rgb(0 0 0 / 0.45);
749
+ }
750
+ .modal.wide { width: min(44rem, calc(100vw - 2rem)); }
751
+ .modal::backdrop { background: rgb(20 20 19 / 0.45); backdrop-filter: blur(2px); }
752
+ .modal[open] { animation: rise 0.16s ease-out; }
753
+ @keyframes rise { from { opacity: 0; transform: translateY(6px); } }
754
+
755
+ .modal-kicker {
756
+ margin: 0 0 0.3rem;
757
+ font-size: 0.7rem;
758
+ font-weight: 600;
759
+ letter-spacing: 0.08em;
760
+ text-transform: uppercase;
761
+ color: var(--accent);
762
+ }
763
+ .modal-kicker:empty { display: none; }
764
+ .modal h2 { font-size: 1.2rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; margin: 0 0 0.3rem; overflow-wrap: anywhere; }
765
+ .modal h3 { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); margin: 1.4rem 0 0.5rem; }
766
+ .modal .hint { color: var(--muted); margin: 0 0 1rem; font-size: 0.88rem; }
767
+
768
+ .preview {
769
+ font-family: var(--mono);
770
+ font-size: 0.78rem;
771
+ line-height: 1.7;
772
+ white-space: pre-wrap;
773
+ overflow-wrap: anywhere;
774
+ background: var(--bg);
775
+ border: 1px solid var(--rule);
776
+ border-radius: var(--radius);
777
+ padding: 0.8rem 0.95rem;
778
+ max-height: 55vh;
779
+ overflow-y: auto;
780
+ margin: 0 0 1.1rem;
781
+ }
782
+ .preview .add, .preview .rem { border-radius: 3px; padding: 0.1em 0.3em; }
783
+ .preview .add { color: var(--add); background: var(--add-soft); }
784
+ .preview .rem { color: var(--rem); background: var(--rem-soft); }
785
+
786
+ .modal-buttons { display: flex; justify-content: flex-end; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.75rem; }
787
+ .modal-buttons button { min-width: 5.5rem; }
788
+ .modal-shortcut-hint { font-size: 0.78rem; color: var(--faint); margin-right: auto; }
222
789
  .modal-head { display: flex; justify-content: space-between; align-items: center; }
223
- .modal input[type="text"], .modal input[type="password"], .modal textarea, .modal select { width: 100%; padding: 0.5rem 0.6rem; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-bg); }
224
- .modal textarea { min-height: 12rem; font-family: var(--gl-font-mono); font-size: 0.85rem; }
225
- .login { display: grid; gap: 0.6rem; }
226
- .login label { display: grid; gap: 0.25rem; font-size: 0.9rem; }
790
+ .modal input[type="text"], .modal input[type="password"], .modal textarea, .modal select {
791
+ width: 100%;
792
+ padding: 0.5rem 0.65rem;
793
+ border: 1px solid var(--rule-strong);
794
+ border-radius: var(--radius);
795
+ background-color: var(--bg);
796
+ }
797
+ .modal select { padding-right: 1.8rem; }
798
+ .modal input:focus, .modal textarea:focus { outline: none; border-color: var(--accent); }
799
+ .modal textarea { min-height: 12rem; font-family: var(--mono); font-size: 0.8rem; }
800
+ .login { display: grid; gap: 0.7rem; }
801
+ .login label { display: grid; gap: 0.3rem; font-size: 0.86rem; font-weight: 500; }
227
802
  .login p { margin: 0; }
228
- .check { display: flex; gap: 0.4rem; align-items: center; font-size: 0.88rem; margin-bottom: 0.5rem; }
229
- .models { list-style: none; margin: 0; padding: 0; max-height: 16rem; overflow-y: auto; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); }
230
- .models li + li { border-top: 1px solid var(--gl-border); }
231
- .models button { width: 100%; text-align: left; border-radius: 0; font-family: var(--gl-font-mono); font-size: 0.85rem; padding: 0.45rem 0.7rem; }
232
- .models button:hover { background: var(--gl-bg); }
233
- .models .current { font-weight: 700; color: var(--mode); }
234
- .models .empty-models { padding: 0.6rem 0.7rem; color: var(--gl-text-muted); font-size: 0.9rem; }
803
+ .check { display: flex; gap: 0.45rem; align-items: center; font-size: 0.88rem; margin-bottom: 0.6rem; }
804
+ .check input { accent-color: var(--accent); }
805
+
806
+ .models {
807
+ list-style: none;
808
+ margin: 0;
809
+ padding: 0;
810
+ max-height: 16rem;
811
+ overflow-y: auto;
812
+ border: 1px solid var(--rule);
813
+ border-radius: var(--radius);
814
+ }
815
+ .models li + li { border-top: 1px solid var(--rule); }
816
+ .models button {
817
+ width: 100%;
818
+ text-align: left;
819
+ border-radius: 0;
820
+ font-family: var(--mono);
821
+ font-size: 0.78rem;
822
+ padding: 0.5rem 0.8rem;
823
+ }
824
+ .models button:hover { background: var(--bg); }
825
+ .models .current { color: var(--accent); font-weight: 600; background: var(--accent-soft); }
826
+ .models .empty-models { padding: 0.65rem 0.8rem; color: var(--muted); font-size: 0.88rem; }
827
+
828
+ /* ---------------------------------------------------------------- narrow screens */
235
829
 
236
830
  .side .phone-only { display: none; }
237
- .settings { display: grid; gap: 0.6rem; }
238
- .settings label { display: grid; gap: 0.25rem; font-size: 0.85rem; color: var(--gl-text-muted); }
239
- .settings select { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-surface-raised); padding: 0.4rem 0.5rem; color: var(--gl-text); }
240
- .settings .model-btn { text-align: left; color: var(--gl-text); }
831
+ .settings { display: grid; gap: 0.6rem; padding: 0 0.3rem; }
832
+ .settings label { display: grid; gap: 0.25rem; font-size: 0.78rem; color: var(--muted); }
833
+ .settings select, .settings button { width: 100%; text-align: left; color: var(--text); }
834
+ .settings .model-btn { font-family: var(--mono); font-size: 0.78rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
835
+
836
+ @media (max-width: 64rem) {
837
+ .composer-hint { display: none; }
838
+ }
241
839
 
242
- /* ---- phone */
243
840
  @media (max-width: 52rem) {
244
- .app { grid-template-columns: minmax(0, 1fr); }
245
- .menu-btn { display: inline-block; border: 1px solid var(--gl-border); }
246
- .side { position: fixed; z-index: 20; top: 0; bottom: 0; left: 0; width: min(20rem, 85vw); transform: translateX(-100%); transition: transform 0.2s ease; box-shadow: 0 0 40px -10px rgba(0,0,0,0.5); }
841
+ .app, .app.side-collapsed { grid-template-columns: minmax(0, 1fr); }
842
+ .app.side-collapsed .side { display: flex; }
843
+ .side {
844
+ position: fixed;
845
+ z-index: 20;
846
+ inset: 0 auto 0 0;
847
+ width: min(19rem, 86vw);
848
+ transform: translateX(-100%);
849
+ transition: transform 0.2s ease;
850
+ box-shadow: var(--shadow);
851
+ }
247
852
  .side.open { transform: none; }
248
- .status { margin-left: 0; width: 100%; }
249
- .status .profile, .status .model-btn { display: none; }
853
+ .top { padding: 0.5rem 0.75rem; gap: 0.5rem; }
854
+ .wide-only { display: none !important; }
855
+ .library .library-text { display: none; }
856
+ .library { padding: 0.3rem; }
250
857
  .side .phone-only { display: grid; }
251
- .top { gap: 0.5rem 0.75rem; }
252
- .log { padding: 1rem 0.75rem 1.5rem; }
253
- .composer { padding: 0.6rem 0.75rem 0.75rem; }
254
- .composer-buttons { flex-direction: column; }
858
+ .log { padding: 1.25rem 0.9rem 1.5rem; }
859
+ .composer { padding: 0 0.75rem 0.75rem; }
860
+ .empty { padding-top: 5vh; }
861
+ }
862
+
863
+ @media (max-width: 30rem) {
864
+ .brand > span { display: none; }
865
+ .modes button { padding: 0.28rem 0.6rem; }
866
+ }
867
+
868
+ @media (prefers-reduced-motion: reduce) {
869
+ *, *::before, *::after { animation: none !important; transition: none !important; }
255
870
  }
256
- @media (prefers-reduced-motion: reduce) { .side { transition: none; } }