@guuey/chat 0.16.7 → 0.16.9

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 (42) hide show
  1. package/README.md +23 -2
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/native/markdown.d.ts +12 -0
  6. package/dist/native/markdown.d.ts.map +1 -1
  7. package/dist/native/markdown.js +21 -0
  8. package/dist/react/components.d.ts +1 -1
  9. package/dist/react/components.d.ts.map +1 -1
  10. package/dist/react/guuey-chat.d.ts +14 -1
  11. package/dist/react/guuey-chat.d.ts.map +1 -1
  12. package/dist/react/guuey-chat.js +27 -7
  13. package/dist/react/markdown.d.ts +9 -0
  14. package/dist/react/markdown.d.ts.map +1 -1
  15. package/dist/react/markdown.js +78 -2
  16. package/dist/react/theme-css.d.ts +8 -0
  17. package/dist/react/theme-css.d.ts.map +1 -1
  18. package/dist/react/theme-css.js +21 -13
  19. package/dist/react/transcript.d.ts +8 -0
  20. package/dist/react/transcript.d.ts.map +1 -1
  21. package/dist/react/transcript.js +2 -2
  22. package/dist/richtext-table.d.ts +26 -0
  23. package/dist/richtext-table.d.ts.map +1 -0
  24. package/dist/richtext-table.js +11 -0
  25. package/dist/strings.d.ts +8 -0
  26. package/dist/strings.d.ts.map +1 -1
  27. package/dist/strings.js +3 -0
  28. package/dist/theme.d.ts +24 -0
  29. package/dist/theme.d.ts.map +1 -1
  30. package/dist/theme.js +44 -2
  31. package/package.json +5 -5
  32. package/src/index.ts +1 -0
  33. package/src/native/markdown.tsx +57 -0
  34. package/src/react/components.tsx +1 -0
  35. package/src/react/guuey-chat.tsx +70 -4
  36. package/src/react/markdown.tsx +103 -1
  37. package/src/react/theme-css.ts +21 -13
  38. package/src/react/transcript.tsx +10 -1
  39. package/src/richtext-table.ts +30 -0
  40. package/src/strings.ts +13 -0
  41. package/src/theme.ts +48 -2
  42. package/styles.css +171 -98
package/src/theme.ts CHANGED
@@ -130,12 +130,20 @@ export type GuueyChatTheme = z.infer<typeof GuueyChatTheme>;
130
130
  * The brand-neutral-but-polished package default — the theme a builder gets
131
131
  * before configuring anything, and the per-token fallback floor every other
132
132
  * theme resolves against.
133
+ *
134
+ * The accent is MONOCHROME (= ink) by founder ruling (guuey#521): an
135
+ * unthemed embed must never carry a foreign accent into a host's product —
136
+ * the old `#2f6bff` blue made every zero-config embed read "off-the-shelf
137
+ * chat vendor" inside someone else's brand (#414's lesson, mirrored). Ink
138
+ * as accent means the send button and user pill render as neutral
139
+ * ink-on-canvas and disappear into any host; a brand accent is a CHOICE
140
+ * (theme prop or one `--guuey-chat-accent` CSS variable), never a default.
133
141
  */
134
142
  export const DEFAULT_CHAT_THEME: GuueyChatTheme = {
135
143
  name: "default",
136
144
  colors: {
137
145
  light: {
138
- accent: "#2f6bff",
146
+ accent: "#111318",
139
147
  onAccent: "#ffffff",
140
148
  ink: "#111318",
141
149
  inkMuted: "#5b6270",
@@ -145,7 +153,7 @@ export const DEFAULT_CHAT_THEME: GuueyChatTheme = {
145
153
  error: "#d64545",
146
154
  },
147
155
  dark: {
148
- accent: "#5c8dff",
156
+ accent: "#e8e9ee",
149
157
  onAccent: "#0b0d12",
150
158
  ink: "#e8e9ee",
151
159
  inkMuted: "#9aa0ac",
@@ -269,6 +277,44 @@ export function resolveTheme(
269
277
  };
270
278
  }
271
279
 
280
+ /**
281
+ * The court-override member a theme DOCUMENT may carry (guuey#519).
282
+ * Values are theme documents themselves (validated by `resolveTheme`'s own
283
+ * lenient parse at resolution time, so a partial or future-schema court
284
+ * entry degrades per-token like any stored theme).
285
+ */
286
+ const CourtOverrides = z
287
+ .object({ courts: z.record(z.string(), z.unknown()).optional() })
288
+ .loose();
289
+
290
+ /**
291
+ * Per-court theme resolution (guuey#519 — the #414 rule generalized).
292
+ *
293
+ * A theme document may carry `courts`: explicit per-court override
294
+ * documents keyed by serving court (`"guuey"`, `"ggui"`, …). A surface
295
+ * resolves ITS court: the court's override resolved per-token OVER the
296
+ * resolved base document when declared, else the base alone. **Brand is
297
+ * never a default** — an undeclared or unknown court gets the neutral
298
+ * base by construction, and readers that never heard of `courts`
299
+ * (lenient parsers projecting only known tokens) keep reading the base
300
+ * untouched, so no court can inherit another court's brand.
301
+ *
302
+ * Resolved themes are court-free: `courts` never survives resolution.
303
+ * NEVER throws; unparseable input degrades exactly as `resolveTheme`.
304
+ */
305
+ export function resolveCourtTheme(
306
+ candidate: unknown,
307
+ court: string,
308
+ base: GuueyChatTheme = DEFAULT_CHAT_THEME,
309
+ ): GuueyChatTheme {
310
+ const resolvedBase = resolveTheme(candidate, base);
311
+ const parsed = CourtOverrides.safeParse(candidate);
312
+ if (!parsed.success) return resolvedBase;
313
+ const override = parsed.data.courts?.[court];
314
+ if (override === undefined) return resolvedBase;
315
+ return resolveTheme(override, resolvedBase);
316
+ }
317
+
272
318
  /** Slot-level merge of two ramp statements (candidate slots win per slot). */
273
319
  function mergeRampSet(
274
320
  base: GuueyChatRampSet | undefined,
package/styles.css CHANGED
@@ -17,10 +17,10 @@
17
17
  flex-direction: column;
18
18
  height: 100%;
19
19
  min-height: 0;
20
- background: var(--guuey-chat-canvas);
21
- color: var(--guuey-chat-ink);
22
- font-family: var(--guuey-chat-font, system-ui, -apple-system, sans-serif);
23
- font-size: calc(15px * var(--guuey-chat-scale, 1));
20
+ background: var(--guuey-chat-canvas, var(--_guuey-chat-canvas));
21
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
22
+ font-family: var(--guuey-chat-font, var(--_guuey-chat-font, system-ui, -apple-system, sans-serif));
23
+ font-size: calc(15px * var(--guuey-chat-scale, var(--_guuey-chat-scale, 1)));
24
24
  line-height: 1.45;
25
25
  }
26
26
 
@@ -34,21 +34,69 @@
34
34
  .guuey-chat-column {
35
35
  display: flex;
36
36
  flex-direction: column;
37
- gap: var(--guuey-chat-gap);
38
- padding: calc(var(--guuey-chat-gap) * 1.5);
37
+ gap: var(--guuey-chat-gap, var(--_guuey-chat-gap));
38
+ padding: calc(var(--guuey-chat-gap, var(--_guuey-chat-gap)) * 1.5);
39
39
  max-width: 48rem;
40
40
  margin-inline: auto;
41
41
  }
42
42
 
43
+ /* ── ui/open-link disclosure (guuey#522) — the URL is SHOWN before any
44
+ navigation; Open is the human's own anchor click. ── */
45
+ .guuey-chat-link-ask {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 8px;
49
+ flex-wrap: wrap;
50
+ margin: 4px calc(var(--guuey-chat-gap) * 1.5);
51
+ padding: 6px 10px;
52
+ border: 1px solid var(--guuey-chat-canvas-muted);
53
+ border-radius: var(--guuey-chat-radius);
54
+ font-size: 0.9em;
55
+ }
56
+ .guuey-chat-link-ask-url {
57
+ color: var(--guuey-chat-ink-muted);
58
+ overflow-wrap: anywhere;
59
+ flex: 1 1 100%;
60
+ }
61
+ .guuey-chat-link-ask-open {
62
+ font-weight: 600;
63
+ }
64
+ .guuey-chat-link-ask-dismiss {
65
+ background: none;
66
+ border: none;
67
+ color: var(--guuey-chat-ink-muted);
68
+ cursor: pointer;
69
+ padding: 0;
70
+ }
71
+
72
+ /* ── R1 tables (guuey#370 — the sdk#23 node) ── */
73
+ .guuey-chat-table-wrap {
74
+ overflow-x: auto; /* wide tables scroll inside the bubble, never the page */
75
+ }
76
+ .guuey-chat-table {
77
+ border-collapse: collapse;
78
+ font-size: 0.95em;
79
+ }
80
+ .guuey-chat-table th,
81
+ .guuey-chat-table td {
82
+ border: 1px solid var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
83
+ padding: 4px 8px;
84
+ text-align: left; /* per-column align from the AST overrides inline */
85
+ }
86
+ .guuey-chat-table th {
87
+ font-weight: 600;
88
+ background: var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
89
+ }
90
+
43
91
  /* ── R0 user ── */
44
92
  .guuey-chat-user {
45
93
  align-self: flex-end;
46
94
  max-width: 85%;
47
95
  }
48
96
  .guuey-chat-user-bubble {
49
- background: var(--guuey-chat-accent);
50
- color: var(--guuey-chat-on-accent);
51
- border-radius: var(--guuey-chat-radius);
97
+ background: var(--guuey-chat-accent, var(--_guuey-chat-accent));
98
+ color: var(--guuey-chat-on-accent, var(--_guuey-chat-on-accent));
99
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
52
100
  border-end-end-radius: 4px;
53
101
  padding: 8px 12px;
54
102
  white-space: pre-wrap;
@@ -60,14 +108,14 @@
60
108
  .guuey-chat-send-failed {
61
109
  margin: 4px 0 0;
62
110
  font-size: 0.85em;
63
- color: var(--guuey-chat-error);
111
+ color: var(--guuey-chat-error, var(--_guuey-chat-error));
64
112
  text-align: end;
65
113
  }
66
114
  .guuey-chat-retry {
67
115
  margin-inline-start: 8px;
68
- border: 1px solid var(--guuey-chat-error);
116
+ border: 1px solid var(--guuey-chat-error, var(--_guuey-chat-error));
69
117
  background: none;
70
- color: var(--guuey-chat-error);
118
+ color: var(--guuey-chat-error, var(--_guuey-chat-error));
71
119
  border-radius: 6px;
72
120
  padding: 1px 8px;
73
121
  cursor: pointer;
@@ -79,13 +127,25 @@
79
127
  .guuey-chat-text {
80
128
  align-self: flex-start;
81
129
  max-width: 92%;
82
- background: var(--guuey-chat-surface);
83
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 8%, transparent);
84
- border-radius: var(--guuey-chat-radius);
130
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
131
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 8%, transparent);
132
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
85
133
  border-end-start-radius: 4px;
86
134
  padding: 8px 12px;
87
135
  overflow-wrap: anywhere;
88
136
  }
137
+ /* The bare surface (guuey#521): assistant text sits directly on the host's
138
+ background — no card, no hairline, no inset — so the transcript reads as
139
+ part of the page it is embedded in. The user pill deliberately stays a
140
+ bubble (the conversational shape survives; only the vendor-styled
141
+ message SURFACE disappears). */
142
+ .guuey-chat--bare .guuey-chat-text {
143
+ max-width: 100%;
144
+ background: none;
145
+ border: 0;
146
+ border-radius: 0;
147
+ padding: 0;
148
+ }
89
149
  .guuey-chat-text p {
90
150
  margin: 0;
91
151
  }
@@ -105,9 +165,9 @@
105
165
  }
106
166
  .guuey-chat-inline-code,
107
167
  .guuey-chat-code-fence {
108
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
168
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
109
169
  font-size: 0.88em;
110
- background: color-mix(in srgb, var(--guuey-chat-ink) 7%, transparent);
170
+ background: color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 7%, transparent);
111
171
  border-radius: 5px;
112
172
  }
113
173
  .guuey-chat-inline-code {
@@ -122,12 +182,12 @@
122
182
  margin: 0;
123
183
  }
124
184
  .guuey-chat-cursor {
125
- color: var(--guuey-chat-accent);
185
+ color: var(--guuey-chat-accent, var(--_guuey-chat-accent));
126
186
  }
127
187
  .guuey-chat-stopped {
128
188
  margin: 6px 0 0;
129
189
  font-size: 0.85em;
130
- color: var(--guuey-chat-ink-muted);
190
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
131
191
  }
132
192
 
133
193
  /* ── Toggles (R2/R3/R4/R9/R15 headers) ── */
@@ -137,7 +197,7 @@
137
197
  gap: 6px;
138
198
  border: 0;
139
199
  background: none;
140
- color: var(--guuey-chat-ink-muted);
200
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
141
201
  font: inherit;
142
202
  font-size: 0.9em;
143
203
  padding: 2px 4px;
@@ -145,10 +205,10 @@
145
205
  cursor: pointer;
146
206
  }
147
207
  .guuey-chat-toggle:hover {
148
- background: color-mix(in srgb, var(--guuey-chat-ink) 6%, transparent);
208
+ background: color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 6%, transparent);
149
209
  }
150
210
  .guuey-chat-toggle:focus-visible {
151
- outline: 2px solid var(--guuey-chat-accent);
211
+ outline: 2px solid var(--guuey-chat-accent, var(--_guuey-chat-accent));
152
212
  outline-offset: 1px;
153
213
  }
154
214
  .guuey-chat-body {
@@ -167,17 +227,17 @@
167
227
  animation: guuey-chat-spin 1s linear infinite;
168
228
  }
169
229
  .guuey-chat-tool-failed {
170
- color: var(--guuey-chat-error);
230
+ color: var(--guuey-chat-error, var(--_guuey-chat-error));
171
231
  }
172
232
  .guuey-chat-tool-note {
173
- color: var(--guuey-chat-ink-muted);
233
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
174
234
  font-size: 0.85em;
175
235
  }
176
236
  .guuey-chat-tool-args,
177
237
  .guuey-chat-data-preview {
178
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
238
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
179
239
  font-size: 0.82em;
180
- background: color-mix(in srgb, var(--guuey-chat-ink) 5%, transparent);
240
+ background: color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 5%, transparent);
181
241
  border-radius: 6px;
182
242
  padding: 6px 8px;
183
243
  margin: 4px 0;
@@ -188,7 +248,7 @@
188
248
  /* ── R4 group ── */
189
249
  .guuey-chat-failure-badge {
190
250
  margin-inline-start: 8px;
191
- color: var(--guuey-chat-error);
251
+ color: var(--guuey-chat-error, var(--_guuey-chat-error));
192
252
  font-size: 0.85em;
193
253
  }
194
254
 
@@ -197,19 +257,19 @@
197
257
  display: flex;
198
258
  gap: 8px;
199
259
  align-items: center;
200
- color: var(--guuey-chat-ink-muted);
260
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
201
261
  font-size: 0.8em;
202
262
  }
203
263
  .guuey-chat-data-empty,
204
264
  .guuey-chat-data-binary {
205
- color: var(--guuey-chat-ink-muted);
265
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
206
266
  font-size: 0.85em;
207
267
  margin: 2px 0;
208
268
  }
209
269
  .guuey-chat-copy {
210
270
  border: 0;
211
271
  background: none;
212
- color: var(--guuey-chat-ink-muted);
272
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
213
273
  font: inherit;
214
274
  font-size: 0.9em;
215
275
  cursor: pointer;
@@ -218,10 +278,10 @@
218
278
 
219
279
  /* ── R6 views ── */
220
280
  .guuey-chat-view {
221
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 8%, transparent);
222
- border-radius: var(--guuey-chat-radius);
281
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 8%, transparent);
282
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
223
283
  overflow: hidden;
224
- background: var(--guuey-chat-surface);
284
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
225
285
  min-height: 3rem;
226
286
  }
227
287
  .guuey-chat-view iframe {
@@ -231,25 +291,25 @@
231
291
  .guuey-chat-view-expired p {
232
292
  margin: 0;
233
293
  padding: 12px;
234
- color: var(--guuey-chat-ink-muted);
294
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
235
295
  font-size: 0.9em;
236
296
  }
237
297
  .guuey-chat-attribution {
238
298
  margin: 0;
239
299
  padding: 4px 12px;
240
- color: var(--guuey-chat-ink-muted);
300
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
241
301
  font-size: 0.78em;
242
- border-top: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 6%, transparent);
302
+ border-top: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 6%, transparent);
243
303
  }
244
304
  /* guuey#204: the promoted-view reference chip — compact, never a frame. */
245
305
  .guuey-chat-view-ref {
246
306
  display: inline-block;
247
307
  margin: 0;
248
308
  padding: 6px 12px;
249
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 12%, transparent);
309
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 12%, transparent);
250
310
  border-radius: 999px;
251
- background: var(--guuey-chat-surface);
252
- color: var(--guuey-chat-ink-muted);
311
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
312
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
253
313
  font-size: 0.85em;
254
314
  line-height: 1.2;
255
315
  }
@@ -259,14 +319,14 @@
259
319
  font-size: 0.85em;
260
320
  }
261
321
  .guuey-chat-view-ref-button:hover {
262
- color: var(--guuey-chat-ink);
263
- border-color: color-mix(in srgb, var(--guuey-chat-ink) 24%, transparent);
322
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
323
+ border-color: color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 24%, transparent);
264
324
  }
265
325
  /* guuey#301 chips presentation: the selected (on-stage) chip + honest expired state. */
266
326
  .guuey-chat-view-ref-selected {
267
- border-color: var(--guuey-chat-accent);
268
- color: var(--guuey-chat-ink);
269
- background: color-mix(in srgb, var(--guuey-chat-accent) 12%, var(--guuey-chat-surface));
327
+ border-color: var(--guuey-chat-accent, var(--_guuey-chat-accent));
328
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
329
+ background: color-mix(in srgb, var(--guuey-chat-accent, var(--_guuey-chat-accent)) 12%, var(--guuey-chat-surface, var(--_guuey-chat-surface)));
270
330
  }
271
331
  .guuey-chat-view-ref-expired {
272
332
  opacity: 0.6;
@@ -277,24 +337,24 @@
277
337
  .guuey-chat-media-image img {
278
338
  max-width: 100%;
279
339
  max-height: var(--guuey-chat-image-cap, 20rem);
280
- border-radius: var(--guuey-chat-radius);
340
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
281
341
  display: block;
282
342
  }
283
343
  .guuey-chat-media-chip {
284
344
  display: inline-block;
285
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 12%, transparent);
345
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 12%, transparent);
286
346
  border-radius: 999px;
287
347
  padding: 2px 10px;
288
348
  font-size: 0.85em;
289
- color: var(--guuey-chat-ink-muted);
349
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
290
350
  }
291
351
 
292
352
  /* ── R8 code ── */
293
353
  .guuey-chat-code pre {
294
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
354
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
295
355
  font-size: 0.85em;
296
- background: color-mix(in srgb, var(--guuey-chat-ink) 6%, transparent);
297
- border-radius: var(--guuey-chat-radius);
356
+ background: color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 6%, transparent);
357
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
298
358
  padding: 10px 12px;
299
359
  margin: 0;
300
360
  max-height: var(--guuey-chat-code-cap, 16rem);
@@ -306,7 +366,7 @@
306
366
  .guuey-chat-code-meta {
307
367
  display: flex;
308
368
  justify-content: space-between;
309
- color: var(--guuey-chat-ink-muted);
369
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
310
370
  font-size: 0.8em;
311
371
  padding: 2px 4px;
312
372
  }
@@ -323,9 +383,9 @@
323
383
 
324
384
  /* ── R10 prompts ── */
325
385
  .guuey-chat-prompt {
326
- border: 1px solid var(--guuey-chat-accent);
327
- border-radius: var(--guuey-chat-radius);
328
- background: var(--guuey-chat-surface);
386
+ border: 1px solid var(--guuey-chat-accent, var(--_guuey-chat-accent));
387
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
388
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
329
389
  padding: 12px;
330
390
  }
331
391
  .guuey-chat-prompt-ask {
@@ -340,21 +400,21 @@
340
400
  border-radius: 8px;
341
401
  padding: 4px 14px;
342
402
  cursor: pointer;
343
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 15%, transparent);
344
- background: var(--guuey-chat-surface);
345
- color: var(--guuey-chat-ink);
403
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 15%, transparent);
404
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
405
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
346
406
  }
347
407
  .guuey-chat-prompt-accept {
348
- background: var(--guuey-chat-accent) !important;
349
- color: var(--guuey-chat-on-accent) !important;
408
+ background: var(--guuey-chat-accent, var(--_guuey-chat-accent)) !important;
409
+ color: var(--guuey-chat-on-accent, var(--_guuey-chat-on-accent)) !important;
350
410
  border-color: transparent !important;
351
411
  }
352
412
  .guuey-chat-prompt-actions button:focus-visible {
353
- outline: 2px solid var(--guuey-chat-accent);
413
+ outline: 2px solid var(--guuey-chat-accent, var(--_guuey-chat-accent));
354
414
  outline-offset: 1px;
355
415
  }
356
416
  .guuey-chat-prompt-record {
357
- color: var(--guuey-chat-ink-muted);
417
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
358
418
  font-size: 0.85em;
359
419
  margin: 0;
360
420
  }
@@ -369,27 +429,27 @@
369
429
  margin: 0;
370
430
  padding: 8px 12px;
371
431
  font-size: 0.85em;
372
- color: var(--guuey-chat-ink);
373
- background: color-mix(in srgb, var(--guuey-chat-accent) 10%, var(--guuey-chat-surface));
374
- border-top: 1px solid var(--guuey-chat-canvas-muted);
432
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
433
+ background: color-mix(in srgb, var(--guuey-chat-accent, var(--_guuey-chat-accent)) 10%, var(--guuey-chat-surface, var(--_guuey-chat-surface)));
434
+ border-top: 1px solid var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
375
435
  }
376
436
  .guuey-chat-oauth-error {
377
- background: color-mix(in srgb, var(--guuey-chat-error) 7%, var(--guuey-chat-surface));
437
+ background: color-mix(in srgb, var(--guuey-chat-error, var(--_guuey-chat-error)) 7%, var(--guuey-chat-surface, var(--_guuey-chat-surface)));
378
438
  }
379
439
  .guuey-chat-oauth-dismiss {
380
440
  font: inherit;
381
441
  cursor: pointer;
382
442
  border: 0;
383
443
  background: transparent;
384
- color: var(--guuey-chat-ink-muted);
444
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
385
445
  text-decoration: underline;
386
446
  }
387
447
 
388
448
  /* ── R11 errors ── */
389
449
  .guuey-chat-error {
390
- border: 1px solid color-mix(in srgb, var(--guuey-chat-error) 45%, transparent);
391
- border-radius: var(--guuey-chat-radius);
392
- background: color-mix(in srgb, var(--guuey-chat-error) 7%, var(--guuey-chat-surface));
450
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-error, var(--_guuey-chat-error)) 45%, transparent);
451
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
452
+ background: color-mix(in srgb, var(--guuey-chat-error, var(--_guuey-chat-error)) 7%, var(--guuey-chat-surface, var(--_guuey-chat-surface)));
393
453
  padding: 10px 12px;
394
454
  }
395
455
  .guuey-chat-error p {
@@ -398,8 +458,8 @@
398
458
  .guuey-chat-error-action {
399
459
  margin-top: 6px;
400
460
  font: inherit;
401
- border: 1px solid var(--guuey-chat-error);
402
- color: var(--guuey-chat-error);
461
+ border: 1px solid var(--guuey-chat-error, var(--_guuey-chat-error));
462
+ color: var(--guuey-chat-error, var(--_guuey-chat-error));
403
463
  background: none;
404
464
  border-radius: 8px;
405
465
  padding: 2px 10px;
@@ -407,45 +467,45 @@
407
467
  }
408
468
  .guuey-chat-error-verbatim {
409
469
  margin: 8px 0 0;
410
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
470
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
411
471
  font-size: 0.8em;
412
- color: var(--guuey-chat-ink-muted);
472
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
413
473
  white-space: pre-wrap;
414
474
  }
415
475
 
416
476
  /* ── R12 status ── */
417
477
  .guuey-chat-status {
418
478
  margin: 0;
419
- color: var(--guuey-chat-ink-muted);
479
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
420
480
  font-size: 0.9em;
421
481
  }
422
482
  .guuey-chat-status-detail {
423
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
483
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
424
484
  font-size: 0.85em;
425
485
  }
426
486
 
427
487
  /* ── R13/R14/R15 ── */
428
488
  .guuey-chat-history {
429
- color: var(--guuey-chat-ink-muted);
489
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
430
490
  text-align: center;
431
491
  font-size: 0.9em;
432
492
  padding: 8px;
433
493
  }
434
494
  .guuey-chat-compaction {
435
- color: var(--guuey-chat-ink-muted);
495
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
436
496
  font-size: 0.8em;
437
497
  text-align: center;
438
- border-top: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 8%, transparent);
498
+ border-top: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 8%, transparent);
439
499
  padding-top: 6px;
440
500
  margin-top: 4px;
441
501
  }
442
502
  .guuey-chat-unknown-type,
443
503
  .guuey-chat-unknown-size {
444
- color: var(--guuey-chat-ink-muted);
504
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
445
505
  font-size: 0.85em;
446
506
  }
447
507
  .guuey-chat-unknown-raw {
448
- font-family: var(--guuey-chat-mono-font, ui-monospace, monospace);
508
+ font-family: var(--guuey-chat-mono-font, var(--_guuey-chat-mono-font, ui-monospace, monospace));
449
509
  font-size: 0.8em;
450
510
  max-height: 16rem;
451
511
  overflow: auto;
@@ -456,9 +516,9 @@
456
516
  align-self: center;
457
517
  font: inherit;
458
518
  font-size: 0.85em;
459
- border: 1px solid color-mix(in srgb, var(--guuey-chat-ink) 12%, transparent);
460
- background: var(--guuey-chat-surface);
461
- color: var(--guuey-chat-ink-muted);
519
+ border: 1px solid color-mix(in srgb, var(--guuey-chat-ink, var(--_guuey-chat-ink)) 12%, transparent);
520
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
521
+ color: var(--guuey-chat-ink-muted, var(--_guuey-chat-ink-muted));
462
522
  border-radius: 999px;
463
523
  padding: 3px 14px;
464
524
  cursor: pointer;
@@ -470,8 +530,8 @@
470
530
  font: inherit;
471
531
  font-size: 0.85em;
472
532
  border: 0;
473
- background: var(--guuey-chat-ink);
474
- color: var(--guuey-chat-canvas);
533
+ background: var(--guuey-chat-ink, var(--_guuey-chat-ink));
534
+ color: var(--guuey-chat-canvas, var(--_guuey-chat-canvas));
475
535
  border-radius: 999px;
476
536
  padding: 6px 14px;
477
537
  cursor: pointer;
@@ -481,7 +541,7 @@
481
541
  .guuey-chat-show-earlier:focus-visible,
482
542
  .guuey-chat-copy:focus-visible,
483
543
  .guuey-chat-retry:focus-visible {
484
- outline: 2px solid var(--guuey-chat-accent);
544
+ outline: 2px solid var(--guuey-chat-accent, var(--_guuey-chat-accent));
485
545
  outline-offset: 1px;
486
546
  }
487
547
 
@@ -526,8 +586,8 @@
526
586
  align-items: flex-end;
527
587
  gap: 8px;
528
588
  padding: 8px 12px;
529
- background: var(--guuey-chat-canvas);
530
- border-top: 1px solid var(--guuey-chat-canvas-muted);
589
+ background: var(--guuey-chat-canvas, var(--_guuey-chat-canvas));
590
+ border-top: 1px solid var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
531
591
  }
532
592
  .guuey-chat-composer-input {
533
593
  flex: 1;
@@ -535,15 +595,28 @@
535
595
  max-height: 9rem;
536
596
  overflow-y: auto;
537
597
  padding: 10px 14px;
538
- border: 1px solid var(--guuey-chat-canvas-muted);
539
- border-radius: var(--guuey-chat-radius);
540
- background: var(--guuey-chat-surface);
541
- color: var(--guuey-chat-ink);
598
+ border: 1px solid var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
599
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
600
+ background: var(--guuey-chat-surface, var(--_guuey-chat-surface));
601
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
542
602
  font: inherit;
543
603
  }
604
+ /* iOS Safari auto-zooms the page when a focused control's font-size is
605
+ under its 16px no-zoom threshold. The kit root is 15px (× scale), and
606
+ this input is `font: inherit` — one px under, so focusing the composer
607
+ zoomed the whole page and the panel visually overflowed the viewport
608
+ (guuey#516, founder real-device report 2026-08-30; the widget loader's
609
+ own width clamp was correct). Floor the input at 16px on touch-primary
610
+ devices only — max() preserves host upscaling (--guuey-chat-scale >
611
+ 16/15), and desktop keeps the 15px look untouched. */
612
+ @media (hover: none) and (pointer: coarse) {
613
+ .guuey-chat-composer-input {
614
+ font-size: max(16px, calc(15px * var(--guuey-chat-scale, var(--_guuey-chat-scale, 1))));
615
+ }
616
+ }
544
617
  .guuey-chat-composer-input:focus {
545
618
  outline: none;
546
- border-color: var(--guuey-chat-accent);
619
+ border-color: var(--guuey-chat-accent, var(--_guuey-chat-accent));
547
620
  }
548
621
  .guuey-chat-composer-input:disabled {
549
622
  opacity: 0.5;
@@ -553,19 +626,19 @@
553
626
  flex-shrink: 0;
554
627
  padding: 10px 16px;
555
628
  border: 0;
556
- border-radius: var(--guuey-chat-radius);
629
+ border-radius: var(--guuey-chat-radius, var(--_guuey-chat-radius));
557
630
  font: inherit;
558
631
  cursor: pointer;
559
632
  }
560
633
  .guuey-chat-composer-send {
561
- background: var(--guuey-chat-accent);
562
- color: var(--guuey-chat-on-accent);
634
+ background: var(--guuey-chat-accent, var(--_guuey-chat-accent));
635
+ color: var(--guuey-chat-on-accent, var(--_guuey-chat-on-accent));
563
636
  }
564
637
  .guuey-chat-composer-send:disabled {
565
638
  cursor: not-allowed;
566
639
  opacity: 0.4;
567
640
  }
568
641
  .guuey-chat-composer-stop {
569
- background: var(--guuey-chat-canvas-muted);
570
- color: var(--guuey-chat-ink);
642
+ background: var(--guuey-chat-canvas-muted, var(--_guuey-chat-canvas-muted));
643
+ color: var(--guuey-chat-ink, var(--_guuey-chat-ink));
571
644
  }