zerochat 7.3.0__py3-none-any.whl

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 (130) hide show
  1. zerochat-7.3.0.dist-info/METADATA +70 -0
  2. zerochat-7.3.0.dist-info/RECORD +130 -0
  3. zerochat-7.3.0.dist-info/WHEEL +5 -0
  4. zerochat-7.3.0.dist-info/entry_points.txt +2 -0
  5. zerochat-7.3.0.dist-info/licenses/LICENSE +34 -0
  6. zerochat-7.3.0.dist-info/top_level.txt +2 -0
  7. zerochat.py +2004 -0
  8. zerochat_runtime/__init__.py +1 -0
  9. zerochat_runtime/assets/css/base.css +199 -0
  10. zerochat_runtime/assets/css/components/composer.css +1258 -0
  11. zerochat_runtime/assets/css/components/debug.css +777 -0
  12. zerochat_runtime/assets/css/components/header.css +97 -0
  13. zerochat_runtime/assets/css/components/icons.css +39 -0
  14. zerochat_runtime/assets/css/components/markdown.css +685 -0
  15. zerochat_runtime/assets/css/components/messages.css +473 -0
  16. zerochat_runtime/assets/css/components/modals.css +1319 -0
  17. zerochat_runtime/assets/css/components/sidebar.css +622 -0
  18. zerochat_runtime/assets/css/components/tools.css +1223 -0
  19. zerochat_runtime/assets/css/layout.css +171 -0
  20. zerochat_runtime/assets/css/print.css +120 -0
  21. zerochat_runtime/assets/css/styles.css +18 -0
  22. zerochat_runtime/assets/css/theme-overrides.css +555 -0
  23. zerochat_runtime/assets/css/tokens.css +165 -0
  24. zerochat_runtime/assets/help/architecture.html +247 -0
  25. zerochat_runtime/assets/help/composer.html +134 -0
  26. zerochat_runtime/assets/help/conversations.html +105 -0
  27. zerochat_runtime/assets/help/debug.html +108 -0
  28. zerochat_runtime/assets/help/en/architecture.html +247 -0
  29. zerochat_runtime/assets/help/en/composer.html +134 -0
  30. zerochat_runtime/assets/help/en/conversations.html +104 -0
  31. zerochat_runtime/assets/help/en/debug.html +105 -0
  32. zerochat_runtime/assets/help/en/gemini-free.html +39 -0
  33. zerochat_runtime/assets/help/en/index.html +191 -0
  34. zerochat_runtime/assets/help/en/learning.html +71 -0
  35. zerochat_runtime/assets/help/en/mcp.html +143 -0
  36. zerochat_runtime/assets/help/en/openrouter-free.html +39 -0
  37. zerochat_runtime/assets/help/en/profiles.html +173 -0
  38. zerochat_runtime/assets/help/en/rag.html +130 -0
  39. zerochat_runtime/assets/help/en/reasoning-telemetry.html +108 -0
  40. zerochat_runtime/assets/help/en/tools-agent.html +133 -0
  41. zerochat_runtime/assets/help/en/webllm.html +355 -0
  42. zerochat_runtime/assets/help/gemini-free.html +39 -0
  43. zerochat_runtime/assets/help/help.css +604 -0
  44. zerochat_runtime/assets/help/help.js +51 -0
  45. zerochat_runtime/assets/help/index.html +194 -0
  46. zerochat_runtime/assets/help/learning.html +71 -0
  47. zerochat_runtime/assets/help/mcp.html +143 -0
  48. zerochat_runtime/assets/help/openrouter-free.html +39 -0
  49. zerochat_runtime/assets/help/profiles.html +174 -0
  50. zerochat_runtime/assets/help/rag.html +130 -0
  51. zerochat_runtime/assets/help/reasoning-telemetry.html +111 -0
  52. zerochat_runtime/assets/help/tools-agent.html +133 -0
  53. zerochat_runtime/assets/help/webllm.html +359 -0
  54. zerochat_runtime/assets/js/agent-core.js +1553 -0
  55. zerochat_runtime/assets/js/api.js +844 -0
  56. zerochat_runtime/assets/js/app.js +2558 -0
  57. zerochat_runtime/assets/js/attachments.js +220 -0
  58. zerochat_runtime/assets/js/charts.js +338 -0
  59. zerochat_runtime/assets/js/chat-engine.js +566 -0
  60. zerochat_runtime/assets/js/config-store.js +207 -0
  61. zerochat_runtime/assets/js/context-manager.js +584 -0
  62. zerochat_runtime/assets/js/conversation-service.js +484 -0
  63. zerochat_runtime/assets/js/cookies.js +688 -0
  64. zerochat_runtime/assets/js/data-reset-service.js +136 -0
  65. zerochat_runtime/assets/js/debug.js +508 -0
  66. zerochat_runtime/assets/js/defaults.js +16 -0
  67. zerochat_runtime/assets/js/export.js +179 -0
  68. zerochat_runtime/assets/js/file-parser.js +2088 -0
  69. zerochat_runtime/assets/js/generation-controller.js +417 -0
  70. zerochat_runtime/assets/js/i18n.js +1483 -0
  71. zerochat_runtime/assets/js/icons.js +156 -0
  72. zerochat_runtime/assets/js/ingestionEngine.js +436 -0
  73. zerochat_runtime/assets/js/markdown.js +588 -0
  74. zerochat_runtime/assets/js/mcp.js +1271 -0
  75. zerochat_runtime/assets/js/message-turns.js +62 -0
  76. zerochat_runtime/assets/js/profile-backup.js +118 -0
  77. zerochat_runtime/assets/js/profile-export-bundle.js +481 -0
  78. zerochat_runtime/assets/js/profile-repository.js +213 -0
  79. zerochat_runtime/assets/js/providers-webllm.js +486 -0
  80. zerochat_runtime/assets/js/providers.js +1560 -0
  81. zerochat_runtime/assets/js/rag-index.js +295 -0
  82. zerochat_runtime/assets/js/rag-service.js +530 -0
  83. zerochat_runtime/assets/js/rag-ui.js +997 -0
  84. zerochat_runtime/assets/js/ragStorage.js +676 -0
  85. zerochat_runtime/assets/js/sandbox.js +449 -0
  86. zerochat_runtime/assets/js/state.js +704 -0
  87. zerochat_runtime/assets/js/storage-db.js +144 -0
  88. zerochat_runtime/assets/js/tool-cards.js +330 -0
  89. zerochat_runtime/assets/js/tool-security.js +653 -0
  90. zerochat_runtime/assets/js/tools/README.md +50 -0
  91. zerochat_runtime/assets/js/tools/builtin/agent-checkpoint.tool.js +212 -0
  92. zerochat_runtime/assets/js/tools/builtin/download-pdf.tool.js +111 -0
  93. zerochat_runtime/assets/js/tools/builtin/execute-javascript.tool.js +219 -0
  94. zerochat_runtime/assets/js/tools/builtin/fetch-web-page.tool.js +112 -0
  95. zerochat_runtime/assets/js/tools/builtin/list-documents.tool.js +117 -0
  96. zerochat_runtime/assets/js/tools/builtin/read-knowledge-chunk.tool.js +129 -0
  97. zerochat_runtime/assets/js/tools/builtin/read-knowledge-image.tool.js +95 -0
  98. zerochat_runtime/assets/js/tools/builtin/render-chart.tool.js +90 -0
  99. zerochat_runtime/assets/js/tools/builtin/search-knowledge-base.tool.js +124 -0
  100. zerochat_runtime/assets/js/tools/builtin/search-web.tool.js +125 -0
  101. zerochat_runtime/assets/js/tools/tool-manifest.js +53 -0
  102. zerochat_runtime/assets/js/tools/tool-runtime.js +77 -0
  103. zerochat_runtime/assets/js/ui-composer.js +319 -0
  104. zerochat_runtime/assets/js/ui-conversation.js +655 -0
  105. zerochat_runtime/assets/js/ui-dialogs.js +132 -0
  106. zerochat_runtime/assets/js/ui-generation-status.js +119 -0
  107. zerochat_runtime/assets/js/ui-inspector.js +804 -0
  108. zerochat_runtime/assets/js/ui-mcp.js +604 -0
  109. zerochat_runtime/assets/js/ui-profiles.js +824 -0
  110. zerochat_runtime/assets/js/ui-reasoning.js +146 -0
  111. zerochat_runtime/assets/js/ui-settings.js +825 -0
  112. zerochat_runtime/assets/js/ui-shell.js +215 -0
  113. zerochat_runtime/assets/js/ui-sidebar.js +429 -0
  114. zerochat_runtime/assets/js/ui-telemetry.js +404 -0
  115. zerochat_runtime/assets/js/ui-transfer.js +262 -0
  116. zerochat_runtime/assets/js/utils.js +216 -0
  117. zerochat_runtime/assets/js/vendor/orama.browser.js +11 -0
  118. zerochat_runtime/assets/js/web-browser.js +569 -0
  119. zerochat_runtime/assets/js/web-search.js +519 -0
  120. zerochat_runtime/assets/manifest.webmanifest +20 -0
  121. zerochat_runtime/assets/services/dummy_mcp/dummy_mcp_server.py +47 -0
  122. zerochat_runtime/assets/services/dummy_mcp/service.json +22 -0
  123. zerochat_runtime/assets/services/lsp/installer.json +9 -0
  124. zerochat_runtime/assets/services/lsp/service.json +22 -0
  125. zerochat_runtime/assets/services/memory/installer.json +9 -0
  126. zerochat_runtime/assets/services/memory/service.json +24 -0
  127. zerochat_runtime/assets/services/playwright/installer.json +10 -0
  128. zerochat_runtime/assets/services/playwright/service.json +39 -0
  129. zerochat_runtime/assets/sw.js +164 -0
  130. zerochat_runtime/assets/zerochat.html +671 -0
@@ -0,0 +1,473 @@
1
+ /* ==========================================================================
2
+ ZeroChat Messages Canvas - Canvas de Lectura Centrado estilo ChatGPT & Gemini
3
+ ========================================================================== */
4
+
5
+ /* Contenedor individual de mensaje (centrado a max-width de lectura) */
6
+ .message-wrapper {
7
+ display: flex;
8
+ flex-direction: column;
9
+ width: 100%;
10
+ max-width: var(--max-content-width, 68rem);
11
+ margin-left: auto;
12
+ margin-right: auto;
13
+ padding: 0 0.5rem;
14
+ min-width: 0;
15
+ /* Sin animación en carga de historial — solo mensajes nuevos se animan */
16
+ }
17
+
18
+ /* Solo los mensajes generados en tiempo real reciben la animación */
19
+ .message-wrapper.is-new-message {
20
+ animation: slideUpFadeIn 0.22s cubic-bezier(0.16, 1, 0.3, 1) both;
21
+ }
22
+
23
+
24
+ .message-wrapper.user {
25
+ align-items: flex-end;
26
+ }
27
+
28
+ .message-wrapper.assistant {
29
+ align-items: flex-start;
30
+ }
31
+
32
+ .message-row {
33
+ display: flex;
34
+ gap: 0.75rem;
35
+ width: 100%;
36
+ min-width: 0;
37
+ }
38
+
39
+ .message-row.user {
40
+ flex-direction: row-reverse;
41
+ }
42
+
43
+ .message-content-wrapper {
44
+ max-width: 100%;
45
+ width: 100%;
46
+ min-width: 0;
47
+ display: flex;
48
+ flex-direction: column;
49
+ }
50
+
51
+ .message-wrapper.user .message-content-wrapper {
52
+ align-items: flex-end;
53
+ }
54
+
55
+ /* Burbuja / Bloque de Contenido */
56
+ .message-content {
57
+ width: fit-content;
58
+ max-width: 100%;
59
+ min-width: 0;
60
+ font-size: 0.935rem;
61
+ line-height: 1.6;
62
+ position: relative;
63
+ word-break: break-word;
64
+ }
65
+
66
+ /* Mensaje del Usuario: Tarjeta limpia y sutil alineada a la derecha */
67
+ .message-row.user .message-content {
68
+ background-color: var(--bg-surface-subtle);
69
+ color: var(--text-main);
70
+ border: 1px solid var(--border-color);
71
+ border-radius: 1.25rem 1.25rem 0.25rem 1.25rem;
72
+ padding: 0.75rem 1.15rem;
73
+ white-space: pre-wrap;
74
+ max-width: 85%;
75
+ box-shadow: var(--shadow-xs);
76
+ }
77
+
78
+ [data-theme="dark"] .message-row.user .message-content {
79
+ background-color: #1e293b;
80
+ color: var(--text-main);
81
+ border-color: #334155;
82
+ }
83
+
84
+ /* Mensaje del Asistente: Sin enmarcado, estilo limpio ChatGPT / Gemini */
85
+ .message-row.assistant .message-content {
86
+ background-color: transparent;
87
+ color: var(--text-main);
88
+ border: none;
89
+ border-radius: 0;
90
+ padding: 0.25rem 0;
91
+ width: 100%;
92
+ min-width: 0;
93
+ text-wrap: pretty;
94
+ box-shadow: none;
95
+ }
96
+
97
+ /* Eliminar margen superior en primer párrafo y margen inferior en último párrafo */
98
+ .message-row.assistant .message-content > p:first-child {
99
+ margin-top: 0;
100
+ }
101
+
102
+ .message-row.assistant .message-content > p:last-child {
103
+ margin-bottom: 0;
104
+ }
105
+
106
+
107
+ /* Mensaje de Error */
108
+ .message-error .message-content {
109
+ background-color: #fee2e2;
110
+ border: 1px solid #fca5a5;
111
+ color: #991b1b;
112
+ border-radius: var(--radius-md);
113
+ padding: 0.75rem 1rem;
114
+ }
115
+
116
+ [data-theme="dark"] .message-error .message-content {
117
+ background-color: rgba(239, 68, 68, 0.15);
118
+ border-color: rgba(239, 68, 68, 0.35);
119
+ color: #fca5a5;
120
+ }
121
+
122
+ /* Fila unificada de pie de mensaje (Estadísticas y Acciones) */
123
+ .message-footer-row {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: flex-start;
127
+ width: 100%;
128
+ gap: 0.5rem;
129
+ margin-top: 0.15rem;
130
+ flex-wrap: wrap;
131
+ }
132
+
133
+ .message-wrapper.user .message-footer-row {
134
+ justify-content: flex-end;
135
+ }
136
+
137
+ /* Estadísticas de respuesta */
138
+ .message-stats {
139
+ display: inline-flex;
140
+ align-items: center;
141
+ gap: 0.5rem;
142
+ font-size: 0.725rem;
143
+ color: var(--text-muted);
144
+ padding: 0.2rem 0.55rem;
145
+ background-color: var(--bg-surface-subtle);
146
+ border: 1px solid var(--border-color);
147
+ border-radius: var(--radius-sm);
148
+ font-family: var(--font-mono);
149
+ width: fit-content;
150
+ margin: 0;
151
+ }
152
+
153
+ .stat-item {
154
+ display: inline-flex;
155
+ align-items: center;
156
+ gap: 0.3rem;
157
+ }
158
+
159
+ .stat-item .ui-icon {
160
+ flex-shrink: 0;
161
+ opacity: 0.85;
162
+ }
163
+
164
+ .stat-item.stat-item-cache {
165
+ color: #0284c7;
166
+ font-weight: 600;
167
+ }
168
+
169
+ @media (max-width: 640px) {
170
+ .message-stats .stat-item:not(.stat-item-speed):not(.stat-item-total),
171
+ .message-stats .stat-sep:not(.stat-sep-2) {
172
+ display: none !important;
173
+ }
174
+
175
+ .message-row.assistant .message-content {
176
+ font-size: 1.0625rem;
177
+ }
178
+ }
179
+
180
+ /* Acciones del mensaje (Copiar, Borrar, Reusar) */
181
+ .message-actions {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: 0.3rem;
185
+ margin: 0;
186
+ opacity: 0.35;
187
+ transition: opacity 0.15s ease;
188
+ margin-left: 0;
189
+ }
190
+
191
+ .message-wrapper:hover .message-actions,
192
+ .message-wrapper:focus-within .message-actions {
193
+ opacity: 1;
194
+ }
195
+
196
+ .btn-msg-action {
197
+ display: inline-flex;
198
+ align-items: center;
199
+ justify-content: center;
200
+ background: transparent;
201
+ border: 1px solid transparent;
202
+ color: var(--text-muted);
203
+ width: 44px;
204
+ height: 44px;
205
+ min-height: 44px;
206
+ padding: 0;
207
+ border-radius: var(--radius-sm);
208
+ cursor: pointer;
209
+ transition: all 0.15s ease;
210
+ }
211
+
212
+ .btn-msg-action .ui-icon {
213
+ width: 18px;
214
+ height: 18px;
215
+ }
216
+
217
+ .btn-msg-action .ui-icon {
218
+ flex-shrink: 0;
219
+ }
220
+
221
+ .btn-msg-action:hover {
222
+ background-color: var(--bg-hover);
223
+ color: var(--text-main);
224
+ border-color: var(--border-color);
225
+ }
226
+
227
+ .btn-msg-action.btn-delete:hover {
228
+ color: var(--danger);
229
+ background-color: #fee2e2;
230
+ border-color: #fca5a5;
231
+ }
232
+
233
+ [data-theme="dark"] .btn-msg-action.btn-delete:hover {
234
+ background-color: rgba(239, 68, 68, 0.2);
235
+ border-color: rgba(239, 68, 68, 0.4);
236
+ }
237
+
238
+ .btn-msg-action.copied {
239
+ color: var(--success);
240
+ }
241
+
242
+ /* Siempre visible en dispositivos touch */
243
+ @media (hover: none) {
244
+ .message-actions {
245
+ opacity: 0.55;
246
+ }
247
+ .message-wrapper:focus-within .message-actions {
248
+ opacity: 1;
249
+ }
250
+ }
251
+
252
+
253
+
254
+ /* Bloque de razonamiento / CoT <think> como acordeón elegante */
255
+ .thought-block {
256
+ margin: 0.85rem 0;
257
+ border-radius: var(--radius-md);
258
+ border: 1px solid var(--border-color);
259
+ border-left: 3px solid var(--primary);
260
+ background-color: var(--bg-surface-subtle);
261
+ overflow: hidden;
262
+ transition: all 0.2s ease;
263
+ /* interpolate-size: permite animar height: auto en el details nativo */
264
+ interpolate-size: allow-keywords;
265
+ }
266
+
267
+ /* Fallback: sin animación si interpolate-size no está disponible */
268
+ @supports not (interpolate-size: allow-keywords) {
269
+ .thought-block { overflow: visible; }
270
+ }
271
+
272
+ .thought-summary {
273
+ display: flex;
274
+ align-items: center;
275
+ gap: 0.45rem;
276
+ padding: 0.5rem 0.85rem;
277
+ cursor: pointer;
278
+ font-weight: 500;
279
+ font-size: 0.825rem;
280
+ color: var(--text-muted);
281
+ background-color: transparent;
282
+ user-select: none;
283
+ transition: color 0.15s, background-color 0.15s;
284
+ }
285
+
286
+ .thought-summary:hover {
287
+ color: var(--text-main);
288
+ background-color: var(--bg-hover);
289
+ }
290
+
291
+ .thought-content {
292
+ padding: 0.75rem 1rem;
293
+ font-size: 0.875rem;
294
+ color: var(--text-secondary);
295
+ line-height: 1.6;
296
+ border-top: 1px solid var(--border-subtle);
297
+ font-style: normal;
298
+ }
299
+
300
+ /* Cursor parpadeante durante streaming */
301
+ .streaming-cursor {
302
+ display: inline-block;
303
+ width: 6px;
304
+ height: 1.15em;
305
+ background-color: var(--primary);
306
+ vertical-align: -0.15em;
307
+ margin-left: 3px;
308
+ border-radius: 1px;
309
+ animation: blink 0.8s infinite;
310
+ }
311
+
312
+ .initial-cursor {
313
+ margin: 0.2rem 0;
314
+ }
315
+
316
+ @keyframes blink {
317
+ 0%, 100% { opacity: 1; }
318
+ 50% { opacity: 0; }
319
+ }
320
+
321
+ /* ==========================================================================
322
+ Indicador de Escritura del Asistente (Typing Indicator — Fase 8)
323
+ ========================================================================== */
324
+ .typing-indicator {
325
+ display: inline-flex;
326
+ align-items: center;
327
+ gap: 5px;
328
+ padding: 0.4rem 0.5rem;
329
+ background-color: transparent;
330
+ border: none;
331
+ border-radius: var(--radius-xl);
332
+ margin-bottom: 0.25rem;
333
+ }
334
+
335
+ .typing-dot {
336
+ width: 7px;
337
+ height: 7px;
338
+ border-radius: 50%;
339
+ background-color: var(--text-muted);
340
+ animation: typingBounce 1.2s ease-in-out infinite;
341
+ flex-shrink: 0;
342
+ }
343
+
344
+ .typing-dot:nth-child(2) { animation-delay: 0.2s; }
345
+ .typing-dot:nth-child(3) { animation-delay: 0.4s; }
346
+
347
+ @media (prefers-reduced-motion: reduce) {
348
+ .typing-dot {
349
+ animation: none;
350
+ opacity: 0.7;
351
+ }
352
+ }
353
+
354
+
355
+ /* Tipografía de Contenido Markdown dentro del Mensaje */
356
+ .message-content h1,
357
+ .message-content h2,
358
+ .message-content h3,
359
+ .message-content h4 {
360
+ margin-top: 1.15rem;
361
+ margin-bottom: 0.45rem;
362
+ font-weight: 700;
363
+ color: var(--text-main);
364
+ line-height: 1.35;
365
+ }
366
+
367
+ .message-content h1 { font-size: 1.35rem; }
368
+ .message-content h2 { font-size: 1.18rem; }
369
+ .message-content h3 { font-size: 1.05rem; }
370
+ .message-content h4 { font-size: 0.95rem; }
371
+
372
+ .message-content p {
373
+ margin-bottom: 0.85rem;
374
+ line-height: 1.65;
375
+ }
376
+
377
+ .message-content p:last-child {
378
+ margin-bottom: 0;
379
+ }
380
+
381
+ .message-content ul,
382
+ .message-content ol {
383
+ padding-left: 1.5rem;
384
+ margin-bottom: 0.85rem;
385
+ }
386
+
387
+ .message-content li {
388
+ margin-bottom: 0.35rem;
389
+ line-height: 1.6;
390
+ }
391
+
392
+ .message-content blockquote {
393
+ border-left: 3px solid var(--primary);
394
+ padding-left: 0.85rem;
395
+ margin: 0.85rem 0;
396
+ color: var(--text-secondary);
397
+ font-style: italic;
398
+ }
399
+
400
+ .message-content code:not(pre code) {
401
+ background-color: var(--code-bg);
402
+ color: var(--code-text);
403
+ padding: 0.15rem 0.4rem;
404
+ border-radius: var(--radius-sm);
405
+ font-family: var(--font-mono);
406
+ font-size: 0.875em;
407
+ border: 1px solid var(--border-color);
408
+ }
409
+
410
+ .message-row.user .message-content code:not(pre code) {
411
+ background-color: rgba(0, 0, 0, 0.06);
412
+ border-color: rgba(0, 0, 0, 0.08);
413
+ color: var(--text-main);
414
+ }
415
+
416
+ [data-theme="dark"] .message-row.user .message-content code:not(pre code) {
417
+ background-color: rgba(255, 255, 255, 0.12);
418
+ border-color: rgba(255, 255, 255, 0.18);
419
+ color: #ffffff;
420
+ }
421
+
422
+ /* ==========================================================================
423
+ Imágenes en Mensajes del Chat
424
+ ========================================================================== */
425
+ .message-content img,
426
+ .message-wrapper img {
427
+ max-width: 100%;
428
+ height: auto;
429
+ box-sizing: border-box;
430
+ }
431
+
432
+ .message-images-grid {
433
+ display: flex;
434
+ flex-wrap: wrap;
435
+ gap: 0.75rem;
436
+ margin-top: 0.75rem;
437
+ width: 100%;
438
+ max-width: 100%;
439
+ }
440
+
441
+ .message-image-item {
442
+ display: flex;
443
+ flex-direction: column;
444
+ max-width: 100%;
445
+ min-width: 0;
446
+ }
447
+
448
+ .message-image-thumb {
449
+ max-width: 100%;
450
+ width: auto;
451
+ height: auto;
452
+ max-height: min(75vh, 560px);
453
+ object-fit: contain;
454
+ border-radius: var(--radius-md);
455
+ border: 1px solid var(--border-color);
456
+ background-color: var(--bg-surface);
457
+ cursor: pointer;
458
+ display: block;
459
+ box-shadow: var(--shadow-xs);
460
+ transition: opacity 0.15s ease, transform 0.15s ease;
461
+ }
462
+
463
+ .message-image-thumb:hover {
464
+ opacity: 0.92;
465
+ }
466
+
467
+ .message-image-caption {
468
+ margin-top: 0.35rem;
469
+ font-size: 0.75rem;
470
+ color: var(--text-muted);
471
+ word-break: break-all;
472
+ max-width: 100%;
473
+ }