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.
Files changed (45) hide show
  1. package/README.md +22 -2
  2. package/app-shell.css +24 -4782
  3. package/colors_and_type.css +43 -0
  4. package/dist/247420.css +74 -3
  5. package/dist/247420.js +16 -16
  6. package/package.json +14 -8
  7. package/src/bootstrap.js +10 -1
  8. package/src/components/chat-message-parts.js +355 -0
  9. package/src/components/chat.js +23 -320
  10. package/src/components/data-density.js +15 -10
  11. package/src/components/files-modals.js +14 -2
  12. package/src/components/files.js +5 -1
  13. package/src/components/freddie/helpers.js +46 -8
  14. package/src/css/app-shell/base.css +157 -0
  15. package/src/css/app-shell/catalog-theme.css +144 -0
  16. package/src/css/app-shell/chat-basic.css +12 -0
  17. package/src/css/app-shell/chat-polish.css +459 -0
  18. package/src/css/app-shell/data-density.css +150 -0
  19. package/src/css/app-shell/files.css +709 -0
  20. package/src/css/app-shell/hero-content.css +407 -0
  21. package/src/css/app-shell/kits-appended.css +361 -0
  22. package/src/css/app-shell/loading-alerts.css +120 -0
  23. package/src/css/app-shell/panel-row.css +177 -0
  24. package/src/css/app-shell/primitives.css +197 -0
  25. package/src/css/app-shell/responsive.css +266 -0
  26. package/src/css/app-shell/responsive2-workspace.css +465 -0
  27. package/src/css/app-shell/row-print.css +75 -0
  28. package/src/css/app-shell/sidebar-misc.css +79 -0
  29. package/src/css/app-shell/states-interactions.css +696 -0
  30. package/src/css/app-shell/topbar.css +319 -0
  31. package/src/deck-stage.js +6 -4
  32. package/src/highlight.js +20 -4
  33. package/src/index.js +15 -5
  34. package/src/kits/os/freddie/pages-chat.js +1 -1
  35. package/src/kits/os/freddie/pages-core.js +1 -1
  36. package/src/kits/os/freddie/pages-os.js +1 -1
  37. package/src/kits/os/freddie/pages-tools.js +1 -1
  38. package/src/kits/os/wm.js +38 -0
  39. package/src/kits/slides/deck-stage-overlay.js +68 -0
  40. package/src/kits/slides/deck-stage-state.js +81 -0
  41. package/src/kits/slides/deck-stage-style.js +117 -0
  42. package/src/kits/slides/deck-stage.js +167 -0
  43. package/src/kits/slides/index.js +5 -0
  44. package/src/markdown.js +89 -11
  45. package/src/kits/os/freddie/helpers.js +0 -33
@@ -0,0 +1,459 @@
1
+ /* ============================================================
2
+ Chat kit polish — styles every class emitted by Chat /
3
+ ChatMessage / ChatComposer / AICat. Before this block the
4
+ chat-* classes had no CSS and rendered as unstyled paragraphs.
5
+ ============================================================ */
6
+ .chat {
7
+ display: flex; flex-direction: column;
8
+ flex: 1; min-height: 0; gap: var(--space-3);
9
+ }
10
+ .chat-head {
11
+ display: flex; align-items: baseline; gap: 8px;
12
+ padding: var(--space-3) 0 var(--space-2);
13
+ font-family: var(--ff-mono); font-size: var(--fs-xs);
14
+ color: var(--fg-3); text-transform: lowercase; letter-spacing: 0.02em;
15
+ border-bottom: 1px solid color-mix(in oklab, var(--fg) 8%, transparent);
16
+ margin-bottom: var(--space-2);
17
+ }
18
+ .chat-head .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
19
+ .chat-head .ds-chat-title,
20
+ .chat-head > span:nth-child(2) {
21
+ font-family: var(--ff-body); font-size: var(--fs-h4);
22
+ font-weight: 600; color: var(--fg);
23
+ text-transform: none; letter-spacing: var(--tr-tight, -0.01em); line-height: 1.2;
24
+ }
25
+ .chat-head .sub { color: var(--fg-3); }
26
+ .chat-head .spread { flex: 1; }
27
+
28
+ .chat-thread {
29
+ display: flex; flex-direction: column; gap: var(--space-3);
30
+ flex: 1; min-height: 0; overflow-y: auto;
31
+ padding: var(--space-2) 0;
32
+ scrollbar-width: thin; scrollbar-color: var(--bg-3) transparent;
33
+ }
34
+ @media (prefers-reduced-motion: no-preference) {
35
+ .chat-thread { scroll-behavior: smooth; }
36
+ }
37
+ .chat-thread::-webkit-scrollbar { width: 8px; }
38
+ .chat-thread::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: var(--r-0); }
39
+ .chat-empty {
40
+ margin: auto;
41
+ text-align: center;
42
+ color: var(--fg-3);
43
+ font-family: var(--ff-mono);
44
+ pointer-events: none;
45
+ }
46
+ .chat-empty-title { font-size: var(--fs-sm); margin: 0 0 var(--space-1); }
47
+ .chat-empty-sub { font-size: var(--fs-tiny); margin: 0; opacity: .7; }
48
+
49
+ .chat-msg { display: flex; gap: 12px; align-items: flex-start; padding: 6px 0; position: relative; min-width: 0; }
50
+ .chat-msg.you { flex-direction: row-reverse; }
51
+ .chat-msg.you .chat-stack { align-items: flex-end; }
52
+ .chat-msg:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); padding: 6px 0; margin: 0; border-radius: var(--r-0); transition: background var(--dur-base) var(--ease); }
53
+
54
+ .chat-avatar {
55
+ width: 36px; height: 36px; flex-shrink: 0;
56
+ border-radius: 50%; background: var(--bg-3); color: var(--fg);
57
+ display: inline-flex; align-items: center; justify-content: center;
58
+ font-family: var(--ff-mono); font-size: 12px; font-weight: 600;
59
+ text-transform: lowercase; letter-spacing: 0.02em; user-select: none;
60
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
61
+ position: relative;
62
+ }
63
+ .chat-msg:hover .chat-avatar { transform: scale(1.03); box-shadow: 0 1px 4px color-mix(in oklab, var(--fg) 6%, transparent); }
64
+ .chat-msg.you .chat-avatar {
65
+ background: color-mix(in oklab, var(--accent) 18%, var(--bg-3));
66
+ color: var(--accent-ink);
67
+ }
68
+ .chat-msg.aicat .chat-avatar {
69
+ background: color-mix(in oklab, var(--mascot) 26%, var(--bg-2));
70
+ color: var(--mascot-deep);
71
+ }
72
+
73
+ .chat-stack {
74
+ display: flex; flex-direction: column; gap: 4px;
75
+ max-width: min(70%, 56ch); min-width: 0;
76
+ flex: 0 1 auto; overflow: hidden;
77
+ }
78
+
79
+ .chat-bubble {
80
+ padding: 10px 14px; background: var(--bg-2); color: var(--fg);
81
+ max-width: 100%;
82
+ border-radius: var(--r-2); line-height: 1.55;
83
+ word-wrap: break-word; overflow-wrap: anywhere;
84
+ font-size: var(--fs-sm);
85
+ min-width: 0;
86
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
87
+ }
88
+ .chat-msg:hover .chat-bubble { transform: translateY(-1px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 6%, transparent); transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease); }
89
+ /* Own bubble — calm tinted lead, not a full electric fill (chat stays readable). */
90
+ .chat-msg.you .chat-bubble { background: var(--accent-tint); color: var(--fg); }
91
+ .chat-msg.aicat .chat-bubble {
92
+ background: color-mix(in oklab, var(--mascot) 14%, var(--bg-2));
93
+ border: 1px solid color-mix(in oklab, var(--mascot) 28%, transparent);
94
+ }
95
+ .chat-bubble code {
96
+ font-family: var(--ff-mono); font-size: 0.92em;
97
+ background: color-mix(in oklab, var(--fg) 10%, transparent);
98
+ padding: 1px 6px; border-radius: var(--r-0);
99
+ }
100
+ .chat-msg.you .chat-bubble code { background: color-mix(in oklab, var(--fg) 10%, transparent); }
101
+ .chat-bubble a {
102
+ color: inherit; text-decoration: underline;
103
+ text-underline-offset: 2px; text-decoration-thickness: 1px;
104
+ text-decoration-color: color-mix(in oklab, currentColor 50%, transparent);
105
+ }
106
+ .chat-bubble a:hover { text-decoration-color: currentColor; }
107
+ .chat-bubble strong { font-weight: 700; }
108
+ .chat-bubble em { font-style: italic; }
109
+
110
+ .chat-bubble.chat-md { line-height: 1.6; }
111
+ .chat-bubble.chat-md > :first-child { margin-top: 0; }
112
+ .chat-bubble.chat-md > :last-child { margin-bottom: 0; }
113
+ .chat-bubble.chat-md h1,
114
+ .chat-bubble.chat-md h2,
115
+ .chat-bubble.chat-md h3,
116
+ .chat-bubble.chat-md h4 {
117
+ font-family: var(--ff-body); font-weight: 600;
118
+ margin: var(--space-2) 0 var(--space-1); line-height: var(--lh-snug);
119
+ }
120
+ .chat-bubble.chat-md h1 { font-size: 1.15em; }
121
+ .chat-bubble.chat-md h2 { font-size: 1.08em; }
122
+ .chat-bubble.chat-md h3 { font-size: 1.04em; }
123
+ .chat-bubble.chat-md p { margin: var(--space-2) 0; }
124
+ .chat-bubble.chat-md ul,
125
+ .chat-bubble.chat-md ol { margin: var(--space-2) 0; padding-left: 22px; }
126
+ .chat-bubble.chat-md li { margin: var(--space-1) 0; }
127
+ .chat-bubble.chat-md blockquote {
128
+ margin: var(--space-2) 0; padding: 4px 12px;
129
+ border-left: 3px solid color-mix(in oklab, currentColor 30%, transparent);
130
+ color: color-mix(in oklab, currentColor 75%, transparent); font-style: italic;
131
+ }
132
+ .chat-bubble.chat-md pre {
133
+ background: var(--bg);
134
+ border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
135
+ padding: 12px 16px; border-radius: var(--r-1); overflow-x: auto;
136
+ font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.55;
137
+ color: var(--fg); margin: var(--space-2) 0;
138
+ }
139
+ /* When injectCodeCopy has wrapped the fence (.chat-code-block), reserve room
140
+ for the absolute .chat-code-lang tab. This selector outranks the bare
141
+ .chat-code-block pre reservation in chat.css, which the 2-class md pre
142
+ selector above would otherwise override. */
143
+ .chat-code-block .chat-bubble.chat-md pre,
144
+ .chat-bubble.chat-md .chat-code-block pre {
145
+ padding-top: calc(var(--space-3) + 4px);
146
+ }
147
+ /* Markdown tables + horizontal rules: agents routinely emit them, but they were
148
+ unstyled (bare unspaced cells, vanished rules). */
149
+ .chat-bubble.chat-md table { border-collapse: collapse; width: auto; max-width: 100%; margin: 8px 0; font-size: .95em; display: block; overflow-x: auto; }
150
+ .chat-bubble.chat-md th,
151
+ .chat-bubble.chat-md td { border: var(--bw-hair) solid var(--rule); padding: 4px 10px; text-align: left; }
152
+ .chat-bubble.chat-md th { background: color-mix(in oklab, var(--fg) 5%, transparent); font-weight: 600; }
153
+ .chat-bubble.chat-md hr { border: 0; border-top: var(--bw-hair) solid var(--rule); margin: 12px 0; }
154
+
155
+ .chat-msg .chat-bubble.chat-code,
156
+ .chat-msg.you .chat-bubble.chat-code,
157
+ .chat-bubble.chat-code {
158
+ padding: 0; background: var(--bg);
159
+ color: var(--fg);
160
+ border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
161
+ overflow: hidden; max-width: 100%; min-width: 0;
162
+ }
163
+ .chat-bubble.chat-code pre,
164
+ .chat-bubble pre,
165
+ .chat-msg pre {
166
+ max-width: 100%;
167
+ overflow-x: auto;
168
+ scrollbar-width: thin;
169
+ scrollbar-color: var(--bg-3) transparent;
170
+ }
171
+ .chat-bubble pre code,
172
+ .chat-msg pre code {
173
+ display: block;
174
+ white-space: pre;
175
+ min-width: 0;
176
+ }
177
+ .chat-code-head {
178
+ display: flex; align-items: center; gap: 10px;
179
+ padding: 8px 12px;
180
+ background: color-mix(in oklab, var(--fg) 6%, var(--bg-2));
181
+ border-bottom: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
182
+ font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3);
183
+ }
184
+ .chat-code-head .lang { text-transform: uppercase; font-weight: 700; color: var(--accent-ink); letter-spacing: 0.06em; }
185
+ .chat-code-head .filename,
186
+ .chat-code-head .name { color: var(--fg-2); font-weight: 500; }
187
+ .chat-code-head .spread { flex: 1; }
188
+ .chat-bubble.chat-code pre {
189
+ margin: 0; padding: 12px 16px; background: transparent;
190
+ font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.55;
191
+ overflow-x: auto; color: var(--fg); border-radius: 0;
192
+ }
193
+ .chat-bubble.chat-code code { background: transparent; padding: 0; font-size: inherit; }
194
+ .chat-bubble.chat-code .token.keyword,
195
+ .chat-bubble.chat-code .token.atrule,
196
+ .chat-bubble.chat-code .token.selector { color: var(--accent-ink); }
197
+ .chat-bubble.chat-code .token.string,
198
+ .chat-bubble.chat-code .token.attr-value { color: var(--code-str-alt, var(--mascot)); }
199
+ .chat-bubble.chat-code .token.comment { color: var(--fg-3); font-style: italic; }
200
+ .chat-bubble.chat-code .token.number,
201
+ .chat-bubble.chat-code .token.boolean { color: var(--code-num, var(--sun)); }
202
+ .chat-bubble.chat-code .token.punctuation { color: var(--fg-2); }
203
+ .chat-bubble.chat-code .token.property,
204
+ .chat-bubble.chat-code .token.attr-name { color: var(--code-keyword, var(--sky)); }
205
+
206
+ .chat-msg.you .chat-image,
207
+ .chat-msg .chat-image,
208
+ .chat-image {
209
+ display: inline-block; border-radius: var(--r-1); overflow: hidden;
210
+ max-width: min(100%, 480px); background: var(--bg-2);
211
+ text-decoration: none; color: var(--fg);
212
+ border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
213
+ transition: box-shadow 0.15s ease, border-color 0.15s ease;
214
+ }
215
+ .chat-msg:hover .chat-image,
216
+ .chat-image:hover {
217
+ border-color: var(--rule);
218
+ }
219
+ .chat-image img { display: block; width: 100%; height: auto; max-height: 360px; object-fit: cover; }
220
+ .chat-image .cap,
221
+ .chat-image .caption { display: block; padding: 8px 12px; font-size: var(--fs-xs); color: var(--fg-3); font-family: var(--ff-mono); }
222
+
223
+ .chat-msg.you .chat-file,
224
+ .chat-msg .chat-file,
225
+ .chat-file {
226
+ display: flex; align-items: center; gap: 12px; padding: 12px 14px;
227
+ background: var(--bg-2); border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
228
+ border-radius: var(--r-1); text-decoration: none; color: var(--fg);
229
+ max-width: min(100%, 360px);
230
+ transition: background var(--dur-snap, .15s) var(--ease, ease), border-color var(--dur-snap, .15s) var(--ease, ease);
231
+ }
232
+ .chat-file:hover { background: var(--bg-3); }
233
+ .chat-file .glyph {
234
+ font-size: 22px; width: 36px; height: 36px;
235
+ display: inline-flex; align-items: center; justify-content: center;
236
+ background: var(--bg-3);
237
+ color: var(--fg-2); border-radius: var(--r-0); flex-shrink: 0; font-family: var(--ff-mono);
238
+ }
239
+ .chat-file > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
240
+ .chat-file .name {
241
+ font-weight: 600; font-size: var(--fs-sm);
242
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
243
+ }
244
+ .chat-file .meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
245
+ .chat-file .size { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
246
+ .chat-file .go { font-family: var(--ff-mono); font-size: 16px; color: var(--fg-3); flex-shrink: 0; }
247
+ .chat-file:hover .go { color: var(--accent-ink); }
248
+
249
+ .chat-msg.you .chat-pdf,
250
+ .chat-msg .chat-pdf,
251
+ .chat-pdf {
252
+ background: var(--bg-2);
253
+ color: var(--fg);
254
+ border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
255
+ border-radius: var(--r-1); overflow: hidden; max-width: min(100%, 480px);
256
+ transition: box-shadow 0.12s ease, border-color 0.12s ease;
257
+ }
258
+ .chat-msg:hover .chat-pdf { border-color: var(--rule); }
259
+ .chat-pdf-head {
260
+ display: flex; align-items: center; gap: 10px; padding: 10px 14px;
261
+ background: color-mix(in oklab, var(--fg) 5%, var(--bg-2));
262
+ border-bottom: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
263
+ }
264
+ .chat-pdf-head .glyph { font-size: 18px; color: var(--mascot); flex-shrink: 0; }
265
+ .chat-pdf-head .name { flex: 1; font-weight: 600; font-size: var(--fs-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
266
+ .chat-pdf-head .size { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
267
+ .chat-pdf-head a { color: var(--accent-ink); font-family: var(--ff-mono); font-size: var(--fs-xs); text-decoration: none; }
268
+ .chat-pdf embed,
269
+ .chat-pdf iframe,
270
+ .chat-pdf object { width: 100%; height: 360px; border: 0; display: block; }
271
+
272
+ .chat-msg.you .chat-link,
273
+ .chat-msg .chat-link,
274
+ .chat-link {
275
+ display: grid; grid-template-columns: 80px 1fr; gap: 12px; padding: 10px;
276
+ background: var(--bg-2);
277
+ border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
278
+ border-radius: var(--r-1); text-decoration: none; color: var(--fg);
279
+ max-width: min(100%, 480px);
280
+ transition: background var(--dur-snap, .15s) var(--ease, ease), border-color var(--dur-snap, .15s) var(--ease, ease), box-shadow 0.15s ease;
281
+ }
282
+ .chat-msg:hover .chat-link,
283
+ .chat-link:hover {
284
+ background: var(--bg-3);
285
+ }
286
+ .chat-link:not(:has(.thumb)):not(:has(img)) { grid-template-columns: 1fr; }
287
+ .chat-link .thumb,
288
+ .chat-link img.thumb { width: 80px; height: 80px; border-radius: var(--r-0); object-fit: cover; background: var(--bg-3) center/cover no-repeat; }
289
+ .chat-link .meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
290
+ .chat-link .host { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); text-transform: lowercase; }
291
+ .chat-link .title { font-weight: 600; font-size: var(--fs-sm); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
292
+ .chat-link .desc { font-size: var(--fs-xs); color: var(--fg-2); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
293
+
294
+ .chat-meta {
295
+ display: flex; align-items: center; gap: 6px;
296
+ font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3);
297
+ padding: 0 6px; letter-spacing: 0.02em;
298
+ }
299
+ .chat-meta .who { font-weight: 600; color: var(--fg-2); }
300
+ .chat-meta .who::after { content: ' ·'; color: var(--fg-3); font-weight: 400; }
301
+ .chat-meta .t { color: var(--fg-3); }
302
+ .chat-meta .tick { color: var(--fg-3); margin-left: 2px; letter-spacing: -2px; font-family: var(--ff-mono); }
303
+ .chat-meta .tick.read { color: var(--accent-ink); }
304
+
305
+ .chat-reactions {
306
+ display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px;
307
+ }
308
+ .chat-reactions .rxn {
309
+ display: inline-flex; align-items: center; gap: 4px;
310
+ padding: 2px 8px; background: var(--bg-2);
311
+ border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
312
+ border-radius: var(--r-pill); font-size: var(--fs-xs);
313
+ cursor: pointer; user-select: none;
314
+ transition: background var(--dur-snap, .12s) var(--ease, ease), border-color var(--dur-snap, .12s) var(--ease, ease), transform 0.12s ease;
315
+ position: relative;
316
+ }
317
+ .chat-reactions .rxn:hover { background: var(--bg-3); transform: scale(1.06); }
318
+ .chat-reactions .rxn.you {
319
+ background: color-mix(in oklab, var(--accent) 18%, var(--bg-2));
320
+ border-color: color-mix(in oklab, var(--accent) 55%, transparent);
321
+ color: var(--accent-ink);
322
+ }
323
+ .chat-reactions .rxn .e { font-size: 14px; line-height: 1; }
324
+ .chat-reactions .rxn .n { font-family: var(--ff-mono); font-weight: 600; font-size: 11px; color: var(--fg-2); }
325
+ .chat-reactions .rxn.you .n { color: var(--accent-ink); }
326
+
327
+ .chat-typing { display: inline-flex; gap: 4px; align-items: center; }
328
+ .chat-typing span {
329
+ width: 6px; height: 6px; border-radius: 50%; background: var(--fg-3);
330
+ }
331
+
332
+ @media (prefers-reduced-motion: no-preference) {
333
+ .chat-typing span {
334
+ animation: chat-typing-bounce 1.4s infinite ease-in-out;
335
+ }
336
+ .chat-typing span:nth-child(1) { animation-delay: 0s; }
337
+ .chat-typing span:nth-child(2) { animation-delay: 0.18s; }
338
+ .chat-typing span:nth-child(3) { animation-delay: 0.36s; }
339
+ @keyframes chat-typing-bounce {
340
+ 0%, 60%, 100% { transform: translateY(0); opacity: 0.55; }
341
+ 30% { transform: translateY(-5px); opacity: 1; }
342
+ }
343
+ }
344
+
345
+ @media (prefers-reduced-motion: no-preference) {
346
+ @keyframes chat-fade-in {
347
+ from { opacity: 0; transform: translateY(8px); }
348
+ to { opacity: 1; transform: translateY(0); }
349
+ }
350
+
351
+ .chat-msg {
352
+ animation: chat-fade-in 0.3s ease-out forwards;
353
+ }
354
+ .chat-msg:nth-child(1) { animation-delay: 0s; }
355
+ .chat-msg:nth-child(2) { animation-delay: 0.05s; }
356
+ .chat-msg:nth-child(3) { animation-delay: 0.1s; }
357
+ .chat-msg:nth-child(n+4) { animation-delay: 0.15s; }
358
+ }
359
+
360
+ /* Calm composer (claude.ai/code): ONE bordered rounded-rect shell holding the
361
+ context line, a borderless textarea, the hint, and an inline send button -
362
+ not a stadium pill + a floating round send. The shell carries the border and
363
+ the focus ring; the textarea fills it transparently. flex-wrap lets the
364
+ context line and hint occupy their own rows above/below the input row. */
365
+ .chat-composer {
366
+ display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--space-2);
367
+ padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
368
+ background: var(--bg);
369
+ /* The composer sits bg-on-bg: the 14% --rule hairline is ~1.3:1 on paper,
370
+ leaving the primary input near-invisible at rest - use the strong rule. */
371
+ border: var(--bw-hair) solid var(--rule-strong);
372
+ border-radius: var(--r-2);
373
+ /* A flat hairline box on a flat background is the single most-repeated
374
+ "looks unfinished" tell in the chat surface - the one control the user
375
+ types into every turn had no more visual weight than a settings card.
376
+ --shadow-1 (already defined kit-wide, just unused here) lifts it a hair
377
+ off the page at rest; the existing focus-within box-shadow overrides it. */
378
+ box-shadow: var(--shadow-1);
379
+ flex-shrink: 0;
380
+ transition: border-color var(--dur-snap) var(--ease), box-shadow var(--dur-snap) var(--ease);
381
+ }
382
+ .chat-composer:focus-within {
383
+ border-color: var(--accent);
384
+ box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 18%, transparent);
385
+ }
386
+ .chat-composer.is-error,
387
+ .chat-composer:has(textarea[aria-invalid="true"]) {
388
+ border-color: var(--flame);
389
+ }
390
+ .chat-composer.is-error:focus-within,
391
+ .chat-composer:has(textarea[aria-invalid="true"]):focus-within {
392
+ box-shadow: 0 0 0 2px color-mix(in oklab, var(--flame) 22%, transparent);
393
+ }
394
+ .chat-composer textarea {
395
+ flex: 1; min-width: 0; padding: 8px 4px;
396
+ background: none; color: var(--fg);
397
+ border: none; border-radius: 0;
398
+ font-family: inherit; font-size: var(--fs-sm);
399
+ /* 1.5 is the value that actually renders (a later polish block used to
400
+ re-declare it; the sizing block now states the truth). */
401
+ line-height: 1.5; resize: none;
402
+ min-height: 28px; max-height: 200px;
403
+ box-sizing: border-box;
404
+ /* Always auto, not focus-only: a capped-height composer that loses focus
405
+ while scrolled must still show its scrollbar - otherwise once the field
406
+ blurs there is zero cue that content exists below the fold. */
407
+ overflow-y: auto;
408
+ scrollbar-width: thin;
409
+ }
410
+ .chat-composer textarea::placeholder { color: var(--fg-3); }
411
+ .chat-composer textarea:focus { background: none; border: none; box-shadow: none; outline: none; }
412
+ .chat-composer .send {
413
+ border-radius: var(--r-1);
414
+ background: var(--accent); color: var(--accent-fg);
415
+ border: 0; cursor: pointer;
416
+ display: inline-flex; align-items: center; justify-content: center;
417
+ flex-shrink: 0;
418
+ transition: background var(--dur-snap, .15s) var(--ease, ease);
419
+ }
420
+ .chat-composer .send:disabled { opacity: .5; cursor: not-allowed; }
421
+ /* Ghost icon buttons in the toolbar (attach / emoji / more). Size + radius are
422
+ owned by .chat-composer-toolbar .composer-btn in chat.css (32px / --r-1,
423
+ 44px coarse); this base rule keeps only the shared appearance. */
424
+ .composer-btn {
425
+ background: transparent; color: var(--fg-3);
426
+ border: 0; cursor: pointer;
427
+ display: inline-flex; align-items: center; justify-content: center;
428
+ flex-shrink: 0;
429
+ transition: background var(--dur-snap, .15s) var(--ease, ease), color var(--dur-snap, .15s) var(--ease, ease);
430
+ }
431
+ .composer-btn:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); color: var(--fg); }
432
+ .chat-composer .send:hover { filter: brightness(0.92); }
433
+ .chat-composer .send:active { filter: brightness(0.94); }
434
+ .chat-composer .send:focus-visible,
435
+ .composer-btn:focus-visible {
436
+ outline: var(--focus-w) solid var(--focus-color);
437
+ outline-offset: var(--focus-offset);
438
+ }
439
+ .chat-composer .send:disabled {
440
+ background: var(--bg-3); color: var(--fg-3); cursor: not-allowed; transform: none;
441
+ }
442
+ @media (prefers-reduced-motion: reduce) {
443
+ .chat-composer,
444
+ .chat-composer textarea,
445
+ .chat-composer .send,
446
+ .composer-btn { transition: none; }
447
+ }
448
+
449
+ .aicat-portrait { display: inline-flex; align-items: center; gap: 10px; padding: 4px 0; }
450
+ .aicat-face {
451
+ width: 32px; height: 32px; font-size: 24px;
452
+ display: inline-flex; align-items: center; justify-content: center;
453
+ background: color-mix(in oklab, var(--mascot) 22%, var(--bg-2));
454
+ border-radius: 50%; flex-shrink: 0;
455
+ }
456
+ .aicat-meta { display: flex; flex-direction: column; font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
457
+ .aicat-meta .name { color: var(--mascot-deep, var(--mascot)); font-weight: 600; }
458
+ [data-theme="dark"] .aicat-meta .name, [data-theme="ink"] .aicat-meta .name { color: var(--mascot); }
459
+
@@ -0,0 +1,150 @@
1
+ /* ============================================================
2
+ Data density — dense observability/dashboard primitives (ported from the
3
+ gmsniff GUI). Components: PhaseWalk, TreeNode, BarRow, StatTile/StatsGrid,
4
+ SubGrid, SessionRow, DevRow, LiveLog/LiveLogEntry. src/components/data-density.js.
5
+ All colors derive from colors_and_type.css tokens — see lint-tokens.mjs.
6
+ ============================================================ */
7
+
8
+ /* --danger-surface: semantic surface for a deviation/error callout background
9
+ (gmsniff's #3a1a1a dark-red-tinted panel). Derived from --warn so it always
10
+ reads as "danger" against the active theme instead of a baked literal. */
11
+ :root {
12
+ --danger-surface: color-mix(in oklab, var(--warn) 14%, var(--bg));
13
+ }
14
+
15
+ /* PhaseWalk */
16
+ .ds-phasewalk { display: inline-flex; gap: 2px; vertical-align: middle; }
17
+ .ds-phasewalk-seg {
18
+ width: 18px; height: 10px; border-radius: var(--r-hair);
19
+ background: var(--bg-3); position: relative;
20
+ }
21
+ .ds-phasewalk-seg.is-reached { background: var(--success); }
22
+ .ds-phasewalk-seg.is-gap { background: var(--warn); }
23
+ /* Standalone PhaseWalk reserves headroom for the labels instead of letting
24
+ them escape upward and overlap the element above. */
25
+ .ds-phasewalk { padding-top: 15px; }
26
+ .ds-phasewalk-lbl {
27
+ position: absolute; top: -15px; left: 0;
28
+ font-size: var(--fs-micro); color: var(--fg-3); white-space: nowrap;
29
+ }
30
+ /* Inline in a single-line SessionRow the labels would overlap the row above —
31
+ segments already carry title tooltips. */
32
+ .ds-session-row .ds-phasewalk { padding-top: 0; }
33
+ .ds-session-row .ds-phasewalk-lbl { display: none; }
34
+
35
+ /* TreeNode */
36
+ .ds-tree-node {
37
+ padding: 5px 10px; border-left: var(--bw-rule) solid var(--bg-3);
38
+ margin: 2px 0 2px 16px; font-size: var(--fs-tiny);
39
+ min-width: 0; overflow-wrap: anywhere;
40
+ }
41
+ @media (max-width: 400px) {
42
+ .ds-tree-node { margin-left: 8px; padding-left: 8px; }
43
+ }
44
+ .ds-tree-node.is-phase { border-color: var(--accent); background: var(--bg-3); font-weight: 600; }
45
+ .ds-tree-node.is-deviation { border-color: var(--warn); background: var(--danger-surface); color: var(--warn); }
46
+ .ds-tree-node.is-mutable-resolve { border-color: var(--success); }
47
+ .ds-tree-node.is-prd-add { border-color: var(--amber); }
48
+ .ds-tree-node-ts { margin-right: 8px; color: var(--fg-3); }
49
+ .ds-tree-node-pills { margin-left: 6px; }
50
+ .ds-tree-node-reason { margin-top: 2px; color: var(--fg-2); }
51
+ .ds-tree-node-deviation { margin-top: 2px; }
52
+ .ds-tree-node-residuals { margin-top: 2px; color: var(--fg-3); }
53
+
54
+ /* BarRow */
55
+ .ds-bar-row { display: flex; align-items: center; gap: 8px; margin: 3px 0; font-size: var(--fs-tiny); }
56
+ .ds-bar-row-label { width: 100px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
57
+ .ds-bar-bg { flex: 1; min-width: 60px; background: var(--bg-3); border-radius: var(--r-hair); height: 6px; overflow: hidden; }
58
+ .ds-bar-fill { background: var(--fg-3); height: 100%; border-radius: var(--r-hair); }
59
+ .ds-bar-fill.is-active { background: var(--accent); }
60
+ .ds-bar-row-value { flex-shrink: 0; color: var(--fg-2); max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
61
+ @media (max-width: 400px) {
62
+ .ds-bar-row-label { width: 72px; }
63
+ }
64
+
65
+ /* StatTile / StatsGrid */
66
+ /* min(140px, 100%) keeps the grid from collapsing to 1 column early inside
67
+ padded panels; the wrapper div stretches its tile to equal row height. */
68
+ .ds-stats-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); gap: var(--space-2); }
69
+ .ds-stats-grid > div { display: grid; }
70
+ @media (max-width: 360px) {
71
+ .ds-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1); }
72
+ }
73
+ .ds-stats-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
74
+ .ds-stat { min-width: 0; background: var(--bg-3); border-radius: var(--r-0); padding: 10px 12px; }
75
+ .ds-stat-val { font-size: clamp(18px, 5cqi, 22px); font-weight: 700; color: var(--accent-ink); overflow-wrap: anywhere; }
76
+ .ds-stat-val.rate-big { font-size: clamp(24px, 7cqi, 32px); color: var(--success); }
77
+ .ds-stat-val.err-rate { font-size: clamp(24px, 7cqi, 32px); color: var(--warn); }
78
+ .ds-stat-lbl { font-size: var(--fs-micro); color: var(--fg-3); margin-top: 2px; }
79
+
80
+ /* Inline row — flex row with centered items and a small gap, for demo/kit
81
+ markup that needs to lay siblings out horizontally without an inline style. */
82
+ .ds-inline-row { display: flex; align-items: center; gap: var(--space-2, 8px); }
83
+
84
+ /* SubGrid */
85
+ .ds-sub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 6px; margin-top: 8px; }
86
+ .ds-sub-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
87
+ .ds-sub-btn {
88
+ padding: 6px 10px; background: var(--bg-3); border: var(--bw-hair) solid var(--bg-3);
89
+ border-radius: var(--r-0); font-size: var(--fs-tiny); cursor: pointer; color: var(--fg);
90
+ text-align: left; font-family: var(--ff-body);
91
+ }
92
+ .ds-sub-btn:hover { border-color: var(--accent); color: var(--accent-ink); }
93
+ .ds-sub-btn span { display: block; font-size: 18px; font-weight: 700; color: var(--accent-ink); }
94
+
95
+ /* SessionRow */
96
+ .ds-session-row {
97
+ display: flex; align-items: center; gap: 8px; padding: 6px 10px;
98
+ flex-wrap: wrap; min-width: 0;
99
+ border-bottom: var(--bw-hair) solid var(--bg-3); cursor: pointer;
100
+ }
101
+ .ds-session-row:hover { background: var(--bg-3); }
102
+ .ds-session-row-id {
103
+ font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--accent-ink);
104
+ flex: 0 1 160px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
105
+ }
106
+ .ds-session-row-counts {
107
+ font-size: var(--fs-micro); color: var(--fg-3);
108
+ flex: 1 1 200px; min-width: 0;
109
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
110
+ }
111
+ @media (max-width: 640px) {
112
+ .ds-session-row-span { flex-basis: 100%; }
113
+ }
114
+ .ds-session-row-devcnt { color: var(--warn); font-weight: 600; }
115
+ .ds-session-row-span { font-size: var(--fs-micro); color: var(--fg-3); }
116
+
117
+ /* DevRow */
118
+ .ds-dev-row {
119
+ background: var(--danger-surface); border-left: var(--bw-chunk) solid var(--warn);
120
+ padding: 8px 12px; margin: 4px 0; border-radius: var(--r-hair); font-size: var(--fs-tiny);
121
+ }
122
+ .ds-dev-row strong { color: var(--warn); }
123
+
124
+ /* LiveLog — natural height with a viewport-tracking cap (dvh follows mobile
125
+ URL-bar chrome; min-height keeps short-landscape from going near-zero). */
126
+ .ds-live-log {
127
+ height: auto;
128
+ max-height: calc(100vh - 200px);
129
+ max-height: calc(100dvh - 200px);
130
+ min-height: 160px;
131
+ overflow-y: auto; overflow-x: hidden;
132
+ font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.5;
133
+ }
134
+ /* Embedded in a WM window the viewport calc is meaningless — fill the container. */
135
+ .fd-root .ds-live-log { height: 100%; max-height: none; min-height: 0; flex: 1 1 auto; }
136
+ .ds-live-log-empty { height: auto; min-height: 0; padding: var(--space-3); color: var(--fg-3); }
137
+ .ds-live-log-entry { padding: 2px 8px; border-bottom: var(--bw-hair) solid var(--bg-3); overflow-wrap: anywhere; }
138
+ .ds-live-log-entry:hover { background: var(--bg-3); }
139
+ .ds-live-log-ts { margin-right: 6px; color: var(--fg-3); }
140
+ .ds-live-log-subtag { margin-right: 6px; padding: 0 5px; border-radius: var(--r-hair); font-size: var(--fs-micro); }
141
+ .ds-live-log-preview { margin-left: 6px; color: var(--fg-3); word-break: break-word; }
142
+
143
+ /* Touch floors for the dense controls (not covered by the mobile width blocks). */
144
+ @media (pointer: coarse) {
145
+ .ds-sub-btn { min-height: 44px; }
146
+ .ds-session-row { min-height: 44px; }
147
+ .ds-live-log-entry { padding-block: 6px; }
148
+ }
149
+
150
+