context_drop 0.1.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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.md +337 -0
  4. data/Rakefile +20 -0
  5. data/SPEC.md +532 -0
  6. data/app/assets/javascripts/context_drop/context_drop.js +3508 -0
  7. data/app/assets/stylesheets/context_drop/application.css +2 -0
  8. data/app/controllers/context_drop/application_controller.rb +114 -0
  9. data/app/controllers/context_drop/attachments_controller.rb +31 -0
  10. data/app/controllers/context_drop/configs_controller.rb +20 -0
  11. data/app/controllers/context_drop/dashboard/feedbacks_controller.rb +107 -0
  12. data/app/controllers/context_drop/feedbacks_controller.rb +208 -0
  13. data/app/controllers/context_drop/health_controller.rb +9 -0
  14. data/app/controllers/context_drop/mcp_controller.rb +67 -0
  15. data/app/helpers/context_drop/widget_helper.rb +62 -0
  16. data/app/javascript/context_drop/__tests__/widget.test.ts +319 -0
  17. data/app/javascript/context_drop/api-client.ts +87 -0
  18. data/app/javascript/context_drop/element-picker.ts +1004 -0
  19. data/app/javascript/context_drop/icons.ts +35 -0
  20. data/app/javascript/context_drop/index.ts +11 -0
  21. data/app/javascript/context_drop/sanitizer.ts +454 -0
  22. data/app/javascript/context_drop/screenshot.ts +214 -0
  23. data/app/javascript/context_drop/styles.ts +690 -0
  24. data/app/javascript/context_drop/types.ts +110 -0
  25. data/app/javascript/context_drop/widget.ts +1120 -0
  26. data/app/models/context_drop/application_record.rb +7 -0
  27. data/app/models/context_drop/attachment.rb +30 -0
  28. data/app/models/context_drop/element_reference.rb +47 -0
  29. data/app/models/context_drop/feedback.rb +94 -0
  30. data/app/services/context_drop/metadata_sanitizer.rb +215 -0
  31. data/app/services/context_drop/upload_validator.rb +217 -0
  32. data/app/views/context_drop/dashboard/feedbacks/index.html.erb +86 -0
  33. data/app/views/context_drop/dashboard/feedbacks/show.html.erb +121 -0
  34. data/app/views/layouts/context_drop/application.html.erb +215 -0
  35. data/config/routes.rb +17 -0
  36. data/db/migrate/20261109000001_create_context_drop_feedbacks.rb +23 -0
  37. data/db/migrate/20261109000002_create_context_drop_element_references.rb +29 -0
  38. data/db/migrate/20261109000003_create_context_drop_attachments.rb +24 -0
  39. data/lib/context_drop/base64_util.rb +15 -0
  40. data/lib/context_drop/configuration.rb +155 -0
  41. data/lib/context_drop/engine.rb +32 -0
  42. data/lib/context_drop/mcp/dispatcher.rb +197 -0
  43. data/lib/context_drop/mcp/prompts/investigate_feedback.rb +83 -0
  44. data/lib/context_drop/mcp/server.rb +25 -0
  45. data/lib/context_drop/mcp/stdio_runner.rb +62 -0
  46. data/lib/context_drop/mcp/tools/get_feedback.rb +133 -0
  47. data/lib/context_drop/mcp/tools/get_feedback_attachment.rb +71 -0
  48. data/lib/context_drop/mcp/tools/list_feedbacks.rb +127 -0
  49. data/lib/context_drop/mcp/tools/update_feedback_status.rb +72 -0
  50. data/lib/context_drop/version.rb +5 -0
  51. data/lib/context_drop.rb +32 -0
  52. data/lib/generators/context_drop/install/install_generator.rb +52 -0
  53. data/lib/generators/context_drop/install/templates/initializer.rb.tt +55 -0
  54. data/lib/tasks/context_drop_tasks.rake +14 -0
  55. metadata +246 -0
@@ -0,0 +1,690 @@
1
+ export const WIDGET_SHADOW_STYLES = `
2
+ :host {
3
+ all: initial;
4
+ --cd-ink: #111318;
5
+ --cd-ink-secondary: #4b5262;
6
+ --cd-ink-subtle: #5c6478;
7
+ --cd-surface: #faf9f6;
8
+ --cd-surface-recessed: #f1efea;
9
+ --cd-surface-elevated: #ffffff;
10
+ --cd-border: #d6d3cd;
11
+ --cd-border-subtle: #e4e1da;
12
+ --cd-pin: #c2410c;
13
+ --cd-pin-hover: #9a3412;
14
+ --cd-pin-soft: #ffedd5;
15
+ --cd-accent: #1d4ed8;
16
+ --cd-accent-hover: #1e40af;
17
+ --cd-accent-soft: #dbeafe;
18
+ --cd-danger: #b91c1c;
19
+ --cd-danger-soft: #fee2e2;
20
+ --cd-success: #15803d;
21
+ --cd-success-soft: #dcfce7;
22
+ --cd-shadow-float: 0 22px 44px -12px rgba(17, 19, 24, 0.22), 0 8px 18px -6px rgba(17, 19, 24, 0.10);
23
+ --cd-shadow-pin: 0 12px 24px -6px rgba(17, 19, 24, 0.24), 0 4px 10px -3px rgba(17, 19, 24, 0.12);
24
+ --cd-radius-lg: 16px;
25
+ --cd-radius-md: 10px;
26
+ --cd-radius-sm: 6px;
27
+ --cd-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
28
+ --cd-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
29
+ --cd-ease: cubic-bezier(0.22, 1, 0.36, 1);
30
+ font-family: var(--cd-font);
31
+ font-size: 13.5px;
32
+ line-height: 1.5;
33
+ color: var(--cd-ink);
34
+ caret-color: var(--cd-pin);
35
+ z-index: 2147483640;
36
+ }
37
+
38
+ *, *::before, *::after {
39
+ box-sizing: border-box;
40
+ }
41
+
42
+ ::selection {
43
+ background: var(--cd-pin-soft);
44
+ color: var(--cd-ink);
45
+ }
46
+
47
+ .cd-root {
48
+ position: fixed;
49
+ z-index: 2147483640;
50
+ display: flex;
51
+ flex-direction: column;
52
+ pointer-events: none;
53
+ max-width: calc(100vw - 24px);
54
+ }
55
+
56
+ .cd-root.pos-top_left {
57
+ top: 20px;
58
+ left: 20px;
59
+ align-items: flex-start;
60
+ }
61
+
62
+ .cd-root.pos-top_right {
63
+ top: 20px;
64
+ right: 20px;
65
+ align-items: flex-end;
66
+ }
67
+
68
+ .cd-root.pos-bottom_left {
69
+ bottom: 20px;
70
+ left: 20px;
71
+ align-items: flex-start;
72
+ }
73
+
74
+ .cd-root.pos-bottom_right {
75
+ bottom: 20px;
76
+ right: 20px;
77
+ align-items: flex-end;
78
+ }
79
+
80
+ .cd-root.is-free-positioned {
81
+ bottom: auto;
82
+ right: auto;
83
+ align-items: flex-start;
84
+ }
85
+
86
+ /* Focus states across all interactive controls */
87
+ button:focus-visible,
88
+ textarea:focus-visible {
89
+ outline: 2px solid var(--cd-accent);
90
+ outline-offset: 2px;
91
+ }
92
+
93
+ /* Custom themed scrollbars */
94
+ .cd-chat-thread::-webkit-scrollbar,
95
+ .cd-tray::-webkit-scrollbar,
96
+ .cd-breadcrumb-scroll::-webkit-scrollbar {
97
+ width: 6px;
98
+ height: 6px;
99
+ }
100
+
101
+ .cd-chat-thread::-webkit-scrollbar-track,
102
+ .cd-tray::-webkit-scrollbar-track,
103
+ .cd-breadcrumb-scroll::-webkit-scrollbar-track {
104
+ background: transparent;
105
+ }
106
+
107
+ .cd-chat-thread::-webkit-scrollbar-thumb,
108
+ .cd-tray::-webkit-scrollbar-thumb,
109
+ .cd-breadcrumb-scroll::-webkit-scrollbar-thumb {
110
+ background: var(--cd-border);
111
+ border-radius: 9999px;
112
+ }
113
+
114
+ /* Freely Floating Pin Trigger Dock */
115
+ .cd-pin-dock {
116
+ pointer-events: auto;
117
+ display: inline-flex;
118
+ align-items: center;
119
+ gap: 2px;
120
+ padding: 4px;
121
+ background: var(--cd-ink);
122
+ color: var(--cd-surface);
123
+ border: 1px solid rgba(250, 249, 246, 0.14);
124
+ border-radius: 9999px 9999px 9999px 6px;
125
+ box-shadow: var(--cd-shadow-pin);
126
+ user-select: none;
127
+ touch-action: none;
128
+ transition: transform 0.18s var(--cd-ease), box-shadow 0.18s var(--cd-ease);
129
+ }
130
+
131
+ .cd-pin-dock[hidden] {
132
+ display: none !important;
133
+ }
134
+
135
+ .cd-pin-dock.is-dragging {
136
+ cursor: grabbing;
137
+ transform: scale(1.03);
138
+ }
139
+
140
+ .cd-pin-dock-grip {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ padding: 4px 3px 4px 5px;
145
+ color: #9ca3b5;
146
+ cursor: grab;
147
+ }
148
+
149
+ .cd-pin-dock-grip:active {
150
+ cursor: grabbing;
151
+ }
152
+
153
+ .cd-floating-pin-btn {
154
+ appearance: none;
155
+ display: inline-flex;
156
+ align-items: center;
157
+ gap: 6px;
158
+ padding: 7px 11px;
159
+ border-radius: 9999px 9999px 9999px 4px;
160
+ border: 0;
161
+ background: var(--cd-pin);
162
+ color: var(--cd-surface);
163
+ font-family: var(--cd-font);
164
+ font-size: 12.5px;
165
+ font-weight: 600;
166
+ cursor: pointer;
167
+ transition: background-color 0.15s var(--cd-ease), transform 0.15s var(--cd-ease);
168
+ }
169
+
170
+ .cd-floating-pin-btn:hover {
171
+ background: var(--cd-pin-hover);
172
+ }
173
+
174
+ .cd-floating-pin-btn.is-active {
175
+ background: var(--cd-accent);
176
+ }
177
+
178
+ .cd-trigger {
179
+ appearance: none;
180
+ display: inline-flex;
181
+ align-items: center;
182
+ gap: 6px;
183
+ padding: 7px 12px;
184
+ border-radius: 9999px;
185
+ border: 0;
186
+ background: transparent;
187
+ color: var(--cd-surface);
188
+ font-family: var(--cd-font);
189
+ font-size: 12.5px;
190
+ font-weight: 600;
191
+ cursor: pointer;
192
+ transition: background-color 0.15s var(--cd-ease);
193
+ }
194
+
195
+ .cd-trigger:hover {
196
+ background: rgba(250, 249, 246, 0.12);
197
+ }
198
+
199
+ .cd-count-pill {
200
+ display: inline-flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ min-width: 18px;
204
+ height: 18px;
205
+ padding: 0 5px;
206
+ border-radius: 9999px;
207
+ background: var(--cd-pin-soft);
208
+ color: var(--cd-pin-hover);
209
+ font-size: 11px;
210
+ font-weight: 700;
211
+ font-variant-numeric: tabular-nums;
212
+ }
213
+
214
+ /* Compact Minimized Bar (active while pinning elements or minimized) */
215
+ .cd-compact-bar {
216
+ pointer-events: auto;
217
+ display: flex;
218
+ align-items: center;
219
+ gap: 8px;
220
+ width: 440px;
221
+ max-width: calc(100vw - 24px);
222
+ padding: 7px 10px;
223
+ background: var(--cd-surface);
224
+ color: var(--cd-ink);
225
+ border: 1px solid var(--cd-border);
226
+ border-radius: 14px;
227
+ box-shadow: var(--cd-shadow-float);
228
+ margin-bottom: 10px;
229
+ user-select: none;
230
+ touch-action: none;
231
+ }
232
+
233
+ .cd-compact-bar[hidden] {
234
+ display: none !important;
235
+ }
236
+
237
+ .cd-compact-status {
238
+ display: flex;
239
+ align-items: center;
240
+ gap: 6px;
241
+ flex: 1;
242
+ min-width: 0;
243
+ }
244
+
245
+ .cd-breadcrumb-scroll {
246
+ display: flex;
247
+ align-items: center;
248
+ gap: 3px;
249
+ overflow-x: auto;
250
+ white-space: nowrap;
251
+ scrollbar-width: thin;
252
+ flex: 1;
253
+ min-width: 0;
254
+ padding: 2px 0;
255
+ }
256
+
257
+ .cd-crumb-btn {
258
+ appearance: none;
259
+ border: 1px solid transparent;
260
+ background: var(--cd-surface-recessed);
261
+ color: var(--cd-ink-secondary);
262
+ font-family: var(--cd-mono);
263
+ font-size: 11px;
264
+ padding: 2px 6px;
265
+ border-radius: 5px;
266
+ cursor: pointer;
267
+ flex-shrink: 0;
268
+ }
269
+
270
+ .cd-crumb-btn:hover {
271
+ border-color: var(--cd-accent);
272
+ color: var(--cd-ink);
273
+ }
274
+
275
+ .cd-crumb-btn.is-current {
276
+ background: var(--cd-accent-soft);
277
+ border-color: var(--cd-accent);
278
+ color: var(--cd-accent-hover);
279
+ font-weight: 600;
280
+ }
281
+
282
+ .cd-crumb-sep {
283
+ display: inline-flex;
284
+ color: var(--cd-ink-subtle);
285
+ flex-shrink: 0;
286
+ }
287
+
288
+ /* Main Floating Chatbox Composer Window */
289
+ .cd-composer {
290
+ pointer-events: auto;
291
+ width: 400px;
292
+ max-width: calc(100vw - 24px);
293
+ background: var(--cd-surface);
294
+ border: 1px solid var(--cd-border);
295
+ border-radius: var(--cd-radius-lg);
296
+ box-shadow: var(--cd-shadow-float);
297
+ margin-bottom: 10px;
298
+ overflow: hidden;
299
+ display: flex;
300
+ flex-direction: column;
301
+ transition: opacity 0.18s var(--cd-ease), transform 0.18s var(--cd-ease);
302
+ }
303
+
304
+ .cd-composer[hidden] {
305
+ display: none !important;
306
+ }
307
+
308
+ .cd-composer.is-dragging-over {
309
+ border-color: var(--cd-accent);
310
+ }
311
+
312
+ /* Chatbox Header with Top-Left Pin Selector & Drag Bar */
313
+ .cd-composer-header {
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: space-between;
317
+ gap: 8px;
318
+ padding: 9px 11px;
319
+ background: var(--cd-surface-recessed);
320
+ border-bottom: 1px solid var(--cd-border);
321
+ cursor: grab;
322
+ user-select: none;
323
+ touch-action: none;
324
+ }
325
+
326
+ .cd-composer-header:active {
327
+ cursor: grabbing;
328
+ }
329
+
330
+ .cd-header-left {
331
+ display: flex;
332
+ align-items: center;
333
+ gap: 8px;
334
+ min-width: 0;
335
+ }
336
+
337
+ /* Pin-Shaped Selector on the Top-Left Corner of the Chatbox */
338
+ .cd-pin-corner-btn {
339
+ appearance: none;
340
+ display: inline-flex;
341
+ align-items: center;
342
+ gap: 6px;
343
+ padding: 6px 10px;
344
+ border-radius: 11px 11px 11px 3px;
345
+ border: 1px solid rgba(194, 65, 12, 0.25);
346
+ background: var(--cd-pin);
347
+ color: var(--cd-surface);
348
+ font-family: var(--cd-font);
349
+ font-size: 12px;
350
+ font-weight: 600;
351
+ cursor: pointer;
352
+ box-shadow: 0 4px 10px -2px rgba(194, 65, 12, 0.28);
353
+ transition: background-color 0.15s var(--cd-ease), transform 0.15s var(--cd-ease);
354
+ }
355
+
356
+ .cd-pin-corner-btn:hover {
357
+ background: var(--cd-pin-hover);
358
+ transform: translateY(-1px);
359
+ }
360
+
361
+ .cd-pin-corner-btn.is-active {
362
+ background: var(--cd-accent);
363
+ border-color: var(--cd-accent);
364
+ box-shadow: 0 4px 10px -2px rgba(29, 78, 216, 0.30);
365
+ }
366
+
367
+ .cd-composer-title {
368
+ font-size: 13px;
369
+ font-weight: 600;
370
+ color: var(--cd-ink);
371
+ margin: 0;
372
+ white-space: nowrap;
373
+ overflow: hidden;
374
+ text-overflow: ellipsis;
375
+ }
376
+
377
+ .cd-header-actions {
378
+ display: flex;
379
+ align-items: center;
380
+ gap: 4px;
381
+ }
382
+
383
+ .cd-icon-btn {
384
+ appearance: none;
385
+ display: inline-flex;
386
+ align-items: center;
387
+ justify-content: center;
388
+ width: 28px;
389
+ height: 28px;
390
+ border: 1px solid transparent;
391
+ background: transparent;
392
+ color: var(--cd-ink-secondary);
393
+ border-radius: 7px;
394
+ cursor: pointer;
395
+ transition: background-color 0.12s ease, color 0.12s ease;
396
+ }
397
+
398
+ .cd-icon-btn:hover {
399
+ background: rgba(17, 19, 24, 0.06);
400
+ color: var(--cd-ink);
401
+ }
402
+
403
+ /* Conversational Chat Thread */
404
+ .cd-chat-thread {
405
+ display: flex;
406
+ flex-direction: column;
407
+ gap: 10px;
408
+ max-height: 230px;
409
+ overflow-y: auto;
410
+ padding: 12px 14px;
411
+ background: var(--cd-surface);
412
+ scrollbar-width: thin;
413
+ }
414
+
415
+ .cd-chat-empty {
416
+ display: flex;
417
+ flex-direction: column;
418
+ gap: 8px;
419
+ padding: 10px 12px;
420
+ background: var(--cd-surface-recessed);
421
+ border: 1px solid var(--cd-border-subtle);
422
+ border-radius: var(--cd-radius-md);
423
+ color: var(--cd-ink-secondary);
424
+ font-size: 12.5px;
425
+ }
426
+
427
+ .cd-chat-empty-text {
428
+ margin: 0;
429
+ color: var(--cd-ink);
430
+ font-weight: 500;
431
+ }
432
+
433
+ .cd-chat-empty-hint {
434
+ margin: 0;
435
+ font-size: 11.5px;
436
+ color: var(--cd-ink-secondary);
437
+ }
438
+
439
+ .cd-chat-msg {
440
+ display: flex;
441
+ flex-direction: column;
442
+ gap: 5px;
443
+ align-self: flex-end;
444
+ max-width: 92%;
445
+ padding: 9px 11px;
446
+ background: var(--cd-surface-elevated);
447
+ border: 1px solid var(--cd-border);
448
+ border-radius: 12px 12px 3px 12px;
449
+ }
450
+
451
+ .cd-chat-msg-text {
452
+ margin: 0;
453
+ font-size: 13px;
454
+ color: var(--cd-ink);
455
+ white-space: pre-wrap;
456
+ word-break: break-word;
457
+ }
458
+
459
+ .cd-chat-msg-meta {
460
+ display: flex;
461
+ align-items: center;
462
+ justify-content: space-between;
463
+ gap: 8px;
464
+ font-size: 11px;
465
+ color: var(--cd-ink-secondary);
466
+ font-variant-numeric: tabular-nums;
467
+ }
468
+
469
+ .cd-chat-msg-pills {
470
+ display: flex;
471
+ flex-wrap: wrap;
472
+ gap: 4px;
473
+ }
474
+
475
+ .cd-chat-msg-pill {
476
+ font-family: var(--cd-mono);
477
+ font-size: 10.5px;
478
+ padding: 1px 6px;
479
+ border-radius: 4px;
480
+ background: var(--cd-surface-recessed);
481
+ border: 1px solid var(--cd-border-subtle);
482
+ color: var(--cd-ink);
483
+ }
484
+
485
+ /* Pinned Elements & Attachments Context Tray */
486
+ .cd-tray {
487
+ display: flex;
488
+ flex-wrap: wrap;
489
+ gap: 6px;
490
+ max-height: 116px;
491
+ overflow-y: auto;
492
+ padding: 8px 12px;
493
+ background: var(--cd-surface-recessed);
494
+ border-top: 1px solid var(--cd-border-subtle);
495
+ scrollbar-width: thin;
496
+ }
497
+
498
+ .cd-tray:empty {
499
+ display: none;
500
+ }
501
+
502
+ .cd-chip {
503
+ display: inline-flex;
504
+ align-items: center;
505
+ gap: 5px;
506
+ max-width: 100%;
507
+ padding: 3px 7px;
508
+ background: var(--cd-surface-elevated);
509
+ border: 1px solid var(--cd-border);
510
+ border-radius: 7px;
511
+ font-size: 11.5px;
512
+ color: var(--cd-ink);
513
+ transition: border-color 0.12s ease;
514
+ }
515
+
516
+ .cd-chip[data-chip-type="element"]:hover {
517
+ border-color: var(--cd-pin);
518
+ }
519
+
520
+ .cd-chip-thumb {
521
+ width: 20px;
522
+ height: 20px;
523
+ border-radius: 4px;
524
+ object-fit: cover;
525
+ border: 1px solid var(--cd-border);
526
+ }
527
+
528
+ .cd-chip-badge {
529
+ display: inline-flex;
530
+ align-items: center;
531
+ gap: 3px;
532
+ font-size: 10px;
533
+ font-weight: 600;
534
+ padding: 1px 5px;
535
+ border-radius: 4px;
536
+ background: var(--cd-pin-soft);
537
+ color: var(--cd-pin-hover);
538
+ }
539
+
540
+ .cd-chip[data-chip-type="screenshot"] .cd-chip-badge,
541
+ .cd-chip[data-chip-type="image"] .cd-chip-badge {
542
+ background: var(--cd-accent-soft);
543
+ color: var(--cd-accent-hover);
544
+ }
545
+
546
+ .cd-chip-label {
547
+ overflow: hidden;
548
+ text-overflow: ellipsis;
549
+ white-space: nowrap;
550
+ max-width: 165px;
551
+ font-family: var(--cd-mono);
552
+ font-size: 11px;
553
+ }
554
+
555
+ .cd-chip-action,
556
+ .cd-chip-remove {
557
+ appearance: none;
558
+ display: inline-flex;
559
+ align-items: center;
560
+ justify-content: center;
561
+ border: 0;
562
+ background: transparent;
563
+ color: var(--cd-ink-secondary);
564
+ cursor: pointer;
565
+ padding: 2px;
566
+ border-radius: 4px;
567
+ line-height: 1;
568
+ }
569
+
570
+ .cd-chip-action:hover {
571
+ color: var(--cd-accent);
572
+ background: var(--cd-accent-soft);
573
+ }
574
+
575
+ .cd-chip-remove:hover {
576
+ color: var(--cd-danger);
577
+ background: var(--cd-danger-soft);
578
+ }
579
+
580
+ /* Status Banner */
581
+ .cd-status {
582
+ padding: 7px 12px;
583
+ font-size: 12px;
584
+ font-weight: 500;
585
+ border-top: 1px solid var(--cd-border-subtle);
586
+ }
587
+
588
+ .cd-status[hidden] {
589
+ display: none !important;
590
+ }
591
+
592
+ .cd-status.error {
593
+ color: var(--cd-danger);
594
+ background: var(--cd-danger-soft);
595
+ }
596
+
597
+ .cd-status.success {
598
+ color: var(--cd-success);
599
+ background: var(--cd-success-soft);
600
+ }
601
+
602
+ /* Chatbox Prompt Input Container */
603
+ .cd-prompt-shell {
604
+ display: flex;
605
+ flex-direction: column;
606
+ background: var(--cd-surface-elevated);
607
+ border-top: 1px solid var(--cd-border);
608
+ }
609
+
610
+ .cd-textarea {
611
+ width: 100%;
612
+ min-height: 68px;
613
+ max-height: 180px;
614
+ resize: vertical;
615
+ border: 0;
616
+ padding: 10px 13px 6px;
617
+ font-family: var(--cd-font);
618
+ font-size: 13.5px;
619
+ line-height: 1.45;
620
+ color: var(--cd-ink);
621
+ background: transparent;
622
+ }
623
+
624
+ .cd-textarea::placeholder {
625
+ color: var(--cd-ink-secondary);
626
+ }
627
+
628
+ .cd-toolbar {
629
+ display: flex;
630
+ align-items: center;
631
+ justify-content: space-between;
632
+ gap: 8px;
633
+ padding: 6px 10px 9px;
634
+ background: var(--cd-surface-elevated);
635
+ }
636
+
637
+ .cd-toolbar-actions {
638
+ display: flex;
639
+ align-items: center;
640
+ gap: 5px;
641
+ flex-wrap: wrap;
642
+ }
643
+
644
+ .cd-btn {
645
+ appearance: none;
646
+ display: inline-flex;
647
+ align-items: center;
648
+ gap: 5px;
649
+ padding: 5px 9px;
650
+ border-radius: 7px;
651
+ border: 1px solid var(--cd-border);
652
+ background: var(--cd-surface);
653
+ color: var(--cd-ink);
654
+ font-family: var(--cd-font);
655
+ font-size: 12px;
656
+ font-weight: 500;
657
+ cursor: pointer;
658
+ transition: background-color 0.12s ease, border-color 0.12s ease;
659
+ }
660
+
661
+ .cd-btn:hover:not(:disabled) {
662
+ background: var(--cd-surface-recessed);
663
+ border-color: var(--cd-ink-secondary);
664
+ }
665
+
666
+ .cd-btn:disabled {
667
+ opacity: 0.5;
668
+ cursor: not-allowed;
669
+ }
670
+
671
+ .cd-btn-primary {
672
+ background: var(--cd-ink);
673
+ border-color: var(--cd-ink);
674
+ color: var(--cd-surface);
675
+ font-weight: 600;
676
+ padding: 6px 12px;
677
+ }
678
+
679
+ .cd-btn-primary:hover:not(:disabled) {
680
+ background: #252a34;
681
+ border-color: #252a34;
682
+ }
683
+
684
+ @media (max-width: 480px) {
685
+ .cd-composer,
686
+ .cd-compact-bar {
687
+ width: calc(100vw - 20px);
688
+ }
689
+ }
690
+ `;