@mrintel/villain-ui 0.3.0 → 0.7.1

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 (140) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3490 -1296
  3. package/dist/components/buttons/Button.svelte +27 -33
  4. package/dist/components/buttons/Button.svelte.d.ts +4 -1
  5. package/dist/components/buttons/ButtonGroup.svelte +17 -30
  6. package/dist/components/buttons/FloatingActionButton.svelte +20 -44
  7. package/dist/components/buttons/FloatingActionButton.svelte.d.ts +2 -1
  8. package/dist/components/buttons/IconButton.svelte +23 -53
  9. package/dist/components/buttons/IconButton.svelte.d.ts +2 -1
  10. package/dist/components/buttons/LinkButton.svelte +24 -37
  11. package/dist/components/buttons/LinkButton.svelte.d.ts +4 -1
  12. package/dist/components/buttons/buttonClasses.d.ts +5 -0
  13. package/dist/components/buttons/buttonClasses.js +8 -3
  14. package/dist/components/cards/Card.svelte +54 -46
  15. package/dist/components/cards/Card.svelte.d.ts +9 -2
  16. package/dist/components/cards/Container.svelte +17 -33
  17. package/dist/components/cards/Divider.svelte +36 -52
  18. package/dist/components/cards/Divider.svelte.d.ts +2 -0
  19. package/dist/components/cards/Grid.svelte +55 -44
  20. package/dist/components/cards/Panel.svelte +18 -32
  21. package/dist/components/cards/Panel.svelte.d.ts +2 -1
  22. package/dist/components/cards/SectionHeader.svelte +24 -38
  23. package/dist/components/cards/SectionHeader.svelte.d.ts +1 -0
  24. package/dist/components/data/Avatar.svelte +48 -67
  25. package/dist/components/data/Badge.svelte +45 -32
  26. package/dist/components/data/Badge.svelte.d.ts +7 -1
  27. package/dist/components/data/CalendarGrid.svelte +433 -0
  28. package/dist/components/data/CalendarGrid.svelte.d.ts +25 -0
  29. package/dist/components/data/CalendarGrid.types.d.ts +7 -0
  30. package/dist/components/data/CalendarGrid.types.js +1 -0
  31. package/dist/components/data/CodeBlock.svelte +119 -121
  32. package/dist/components/data/CodeBlock.svelte.d.ts +8 -0
  33. package/dist/components/data/List.svelte +87 -64
  34. package/dist/components/data/List.svelte.d.ts +7 -0
  35. package/dist/components/data/Pagination.svelte +121 -123
  36. package/dist/components/data/Pagination.svelte.d.ts +5 -0
  37. package/dist/components/data/Sparkline.svelte +117 -0
  38. package/dist/components/data/Sparkline.svelte.d.ts +43 -0
  39. package/dist/components/data/Stat.svelte +92 -103
  40. package/dist/components/data/Table.svelte +443 -76
  41. package/dist/components/data/Table.svelte.d.ts +23 -2
  42. package/dist/components/data/Table.types.d.ts +14 -0
  43. package/dist/components/data/Table.types.js +1 -0
  44. package/dist/components/data/Tag.svelte +51 -53
  45. package/dist/components/data/Tag.svelte.d.ts +5 -1
  46. package/dist/components/data/index.d.ts +4 -0
  47. package/dist/components/data/index.js +2 -0
  48. package/dist/components/forms/Checkbox.svelte +39 -51
  49. package/dist/components/forms/Checkbox.svelte.d.ts +3 -1
  50. package/dist/components/forms/DatePicker.svelte +61 -0
  51. package/dist/components/forms/DatePicker.svelte.d.ts +15 -0
  52. package/dist/components/forms/DateTimePicker.svelte +63 -0
  53. package/dist/components/forms/DateTimePicker.svelte.d.ts +16 -0
  54. package/dist/components/forms/FileUpload.svelte +136 -164
  55. package/dist/components/forms/FileUpload.svelte.d.ts +1 -0
  56. package/dist/components/forms/Input.svelte +284 -57
  57. package/dist/components/forms/Input.svelte.d.ts +10 -3
  58. package/dist/components/forms/InputGroup.svelte +7 -7
  59. package/dist/components/forms/RadioGroup.svelte +77 -87
  60. package/dist/components/forms/RadioGroup.svelte.d.ts +3 -1
  61. package/dist/components/forms/RangeSlider.svelte +90 -116
  62. package/dist/components/forms/Select.svelte +106 -71
  63. package/dist/components/forms/Select.svelte.d.ts +3 -1
  64. package/dist/components/forms/Step.svelte +25 -0
  65. package/dist/components/forms/Step.svelte.d.ts +12 -0
  66. package/dist/components/forms/StepContext.d.ts +3 -0
  67. package/dist/components/forms/StepContext.js +5 -0
  68. package/dist/components/forms/Stepper.types.d.ts +37 -0
  69. package/dist/components/forms/Stepper.types.js +1 -0
  70. package/dist/components/forms/StepperForm.svelte +183 -0
  71. package/dist/components/forms/StepperForm.svelte.d.ts +17 -0
  72. package/dist/components/forms/Switch.svelte +44 -56
  73. package/dist/components/forms/Switch.svelte.d.ts +3 -1
  74. package/dist/components/forms/Textarea.svelte +52 -57
  75. package/dist/components/forms/Textarea.svelte.d.ts +3 -1
  76. package/dist/components/forms/TimePicker.svelte +63 -0
  77. package/dist/components/forms/TimePicker.svelte.d.ts +16 -0
  78. package/dist/components/forms/formClasses.d.ts +3 -0
  79. package/dist/components/forms/formClasses.js +3 -0
  80. package/dist/components/forms/index.d.ts +6 -0
  81. package/dist/components/forms/index.js +5 -0
  82. package/dist/components/navigation/Breadcrumbs.svelte +56 -59
  83. package/dist/components/navigation/Breadcrumbs.svelte.d.ts +1 -0
  84. package/dist/components/navigation/ContextMenu.svelte +133 -83
  85. package/dist/components/navigation/ContextMenu.svelte.d.ts +8 -1
  86. package/dist/components/navigation/DropdownMenu.svelte +139 -80
  87. package/dist/components/navigation/DropdownMenu.svelte.d.ts +8 -1
  88. package/dist/components/navigation/Menu.svelte +72 -48
  89. package/dist/components/navigation/Navbar.svelte +111 -32
  90. package/dist/components/navigation/Navbar.svelte.d.ts +6 -0
  91. package/dist/components/navigation/Sidebar.svelte +236 -35
  92. package/dist/components/navigation/Sidebar.svelte.d.ts +2 -0
  93. package/dist/components/navigation/Stepper.svelte +204 -0
  94. package/dist/components/navigation/Stepper.svelte.d.ts +34 -0
  95. package/dist/components/navigation/Tabs.svelte +86 -54
  96. package/dist/components/navigation/Tabs.svelte.d.ts +5 -1
  97. package/dist/components/navigation/index.d.ts +1 -0
  98. package/dist/components/navigation/index.js +1 -0
  99. package/dist/components/overlays/Alert.svelte +81 -99
  100. package/dist/components/overlays/Alert.svelte.d.ts +5 -1
  101. package/dist/components/overlays/CommandPalette.svelte +182 -217
  102. package/dist/components/overlays/Drawer.svelte +158 -167
  103. package/dist/components/overlays/Drawer.svelte.d.ts +3 -1
  104. package/dist/components/overlays/Dropdown.svelte +62 -30
  105. package/dist/components/overlays/Dropdown.svelte.d.ts +2 -0
  106. package/dist/components/overlays/Modal.svelte +125 -130
  107. package/dist/components/overlays/Modal.svelte.d.ts +3 -1
  108. package/dist/components/overlays/Popover.svelte +106 -131
  109. package/dist/components/overlays/ProgressBar.svelte +29 -45
  110. package/dist/components/overlays/SkeletonLoader.svelte +66 -82
  111. package/dist/components/overlays/Spinner.svelte +33 -43
  112. package/dist/components/overlays/Toast.svelte +111 -140
  113. package/dist/components/overlays/Toast.svelte.d.ts +3 -0
  114. package/dist/components/overlays/Tooltip.svelte +94 -115
  115. package/dist/components/overlays/Tooltip.svelte.d.ts +3 -1
  116. package/dist/components/typography/Code.svelte +10 -14
  117. package/dist/components/typography/Heading.svelte +15 -22
  118. package/dist/components/typography/Heading.svelte.d.ts +1 -0
  119. package/dist/components/typography/Text.svelte +21 -24
  120. package/dist/components/typography/Text.svelte.d.ts +2 -1
  121. package/dist/components/utilities/Accordion.svelte +54 -67
  122. package/dist/components/utilities/Accordion.svelte.d.ts +4 -1
  123. package/dist/components/utilities/Carousel.svelte +124 -152
  124. package/dist/components/utilities/Collapse.svelte +46 -60
  125. package/dist/components/utilities/Hero.svelte +42 -0
  126. package/dist/components/utilities/Hero.svelte.d.ts +10 -0
  127. package/dist/components/utilities/Portal.svelte +47 -72
  128. package/dist/components/utilities/ScrollArea.svelte +33 -41
  129. package/dist/components/utilities/SystemConsole.svelte +310 -0
  130. package/dist/components/utilities/SystemConsole.svelte.d.ts +20 -0
  131. package/dist/components/utilities/SystemInterface.svelte +726 -0
  132. package/dist/components/utilities/SystemInterface.svelte.d.ts +19 -0
  133. package/dist/components/utilities/index.d.ts +4 -0
  134. package/dist/components/utilities/index.js +3 -0
  135. package/dist/components/utilities/utilities.types.d.ts +46 -0
  136. package/dist/components/utilities/utilities.types.js +4 -0
  137. package/dist/index.d.ts +57 -5
  138. package/dist/index.js +5 -5
  139. package/dist/theme.css +2889 -218
  140. package/package.json +83 -76
@@ -0,0 +1,726 @@
1
+ <script lang="ts">let { messages = [], onSubmit, processing = false, placeholder = 'ENTER DIRECTIVE', height = '600px', autoScroll = true, stagingDelay = 150, leftPanel, rightPanel, topPanel, bottomPanel, class: className = '', ...restProps } = $props();
2
+ let inputValue = $state('');
3
+ let outputContainer = $state();
4
+ let inputElement = $state();
5
+ let visibleMessages = $state(new Set());
6
+ let processingDots = $state(0);
7
+ // Auto-scroll when messages change
8
+ $effect(() => {
9
+ if (autoScroll && outputContainer && messages.length > 0) {
10
+ requestAnimationFrame(() => {
11
+ if (outputContainer) {
12
+ outputContainer.scrollTop = outputContainer.scrollHeight;
13
+ }
14
+ });
15
+ }
16
+ });
17
+ // Staged message revelation
18
+ $effect(() => {
19
+ const newMessages = messages.filter((m) => !visibleMessages.has(m.id));
20
+ if (newMessages.length === 0)
21
+ return;
22
+ // Stage messages with delay
23
+ newMessages.forEach((msg, index) => {
24
+ setTimeout(() => {
25
+ visibleMessages.add(msg.id);
26
+ visibleMessages = new Set(visibleMessages);
27
+ }, index * stagingDelay);
28
+ });
29
+ });
30
+ // Processing animation
31
+ $effect(() => {
32
+ if (!processing) {
33
+ processingDots = 0;
34
+ return;
35
+ }
36
+ const interval = setInterval(() => {
37
+ processingDots = (processingDots + 1) % 4;
38
+ }, 400);
39
+ return () => clearInterval(interval);
40
+ });
41
+ function handleSubmit(e) {
42
+ e.preventDefault();
43
+ const trimmed = inputValue.trim();
44
+ if (!trimmed || !onSubmit || processing)
45
+ return;
46
+ onSubmit(trimmed);
47
+ inputValue = '';
48
+ }
49
+ function handleKeyDown(e) {
50
+ if (e.key === 'Enter' && !e.shiftKey && !processing) {
51
+ e.preventDefault();
52
+ handleSubmit(e);
53
+ }
54
+ }
55
+ function getTierStyles(tier) {
56
+ const tiers = {
57
+ informational: 'text-[var(--color-accent-soft)] border-l-[var(--color-accent-overlay-30)]',
58
+ analysis: 'text-[#60a5fa] border-l-[rgba(96,165,250,0.3)]',
59
+ directive: 'text-[var(--color-accent)] border-l-[var(--color-accent-overlay-50)]',
60
+ warning: 'text-[var(--color-warning)] border-l-[rgba(251,191,36,0.3)]',
61
+ critical: 'text-[var(--color-error)] border-l-[var(--color-error-overlay-50)]'
62
+ };
63
+ return tier ? tiers[tier] : tiers.informational;
64
+ }
65
+ function formatTimestamp(ts) {
66
+ if (!ts)
67
+ return '';
68
+ const date = new Date(ts);
69
+ const hours = date.getHours().toString().padStart(2, '0');
70
+ const minutes = date.getMinutes().toString().padStart(2, '0');
71
+ const seconds = date.getSeconds().toString().padStart(2, '0');
72
+ const ms = date.getMilliseconds().toString().padStart(3, '0');
73
+ return `${hours}:${minutes}:${seconds}.${ms}`;
74
+ }
75
+ function getContent(content) {
76
+ if (typeof content === 'string') {
77
+ return { type: 'text', value: content };
78
+ }
79
+ return content;
80
+ }
81
+ function getStatusColor(status) {
82
+ const colors = {
83
+ ok: 'var(--color-success)',
84
+ warning: 'var(--color-warning)',
85
+ error: 'var(--color-error)',
86
+ info: 'var(--color-accent)'
87
+ };
88
+ return colors[status];
89
+ }
90
+ const containerStyle = $derived(`height: ${height}`);
91
+ const hasPanel = $derived(!!leftPanel || !!rightPanel || !!topPanel || !!bottomPanel);
92
+ export {};
93
+ </script>
94
+
95
+ <div
96
+ class="system-interface {className}"
97
+ class:has-panels={hasPanel}
98
+ style={containerStyle}
99
+ {...restProps}
100
+ role="log"
101
+ aria-live="polite"
102
+ aria-atomic="false"
103
+ >
104
+ <!-- Header -->
105
+ <div class="interface-header">
106
+ <div class="header-line"></div>
107
+ <div class="header-title">
108
+ <span class="title-text">SYSTEM INTERFACE</span>
109
+ {#if processing}
110
+ <span class="processing-indicator">
111
+ PROCESSING{'.'.repeat(processingDots)}
112
+ </span>
113
+ {/if}
114
+ </div>
115
+ <div class="header-line"></div>
116
+ </div>
117
+
118
+ <!-- Top Panel (optional persistent area) -->
119
+ {#if topPanel}
120
+ <div class="top-panel">
121
+ {@render topPanel()}
122
+ </div>
123
+ {/if}
124
+
125
+ <!-- Main Content Area -->
126
+ <div class="interface-content">
127
+ <!-- Left Panel (optional) -->
128
+ {#if leftPanel}
129
+ <div class="side-panel left-panel">
130
+ {@render leftPanel()}
131
+ </div>
132
+ {/if}
133
+
134
+ <!-- Message Stream -->
135
+ <div class="message-stream" bind:this={outputContainer}>
136
+ {#each messages as message (message.id)}
137
+ {@const isVisible = visibleMessages.has(message.id)}
138
+ {@const contentData = getContent(message.content)}
139
+ <div
140
+ class="message-wrapper"
141
+ class:visible={isVisible}
142
+ class:updateable={message.updateable}
143
+ data-role={message.role}
144
+ data-tier={message.tier}
145
+ data-type={contentData.type}
146
+ >
147
+ {#if message.role === 'user'}
148
+ <!-- User Input -->
149
+ <div class="user-message">
150
+ <div class="message-meta">
151
+ <span class="message-role">USER</span>
152
+ {#if message.timestamp}
153
+ <span class="message-timestamp">{formatTimestamp(message.timestamp)}</span>
154
+ {/if}
155
+ </div>
156
+ <div class="message-content user-content">
157
+ {#if contentData.type === 'text'}
158
+ {contentData.value}
159
+ {:else if typeof message.content === 'string'}
160
+ {message.content}
161
+ {/if}
162
+ </div>
163
+ </div>
164
+ {:else}
165
+ <!-- System Output -->
166
+ <div class="system-message {getTierStyles(message.tier)}">
167
+ <div class="message-meta">
168
+ <span class="message-role">SYSTEM</span>
169
+ {#if message.tier}
170
+ <span class="tier-indicator">{message.tier.toUpperCase()}</span>
171
+ {/if}
172
+ <span class="content-type">{contentData.type.toUpperCase()}</span>
173
+ {#if message.timestamp}
174
+ <span class="message-timestamp">{formatTimestamp(message.timestamp)}</span>
175
+ {/if}
176
+ </div>
177
+ <div class="message-content system-content">
178
+ {#if contentData.type === 'text'}
179
+ <div class="text-content">{contentData.value}</div>
180
+ {:else if contentData.type === 'stats'}
181
+ <div class="stats-content" class:grid-layout={contentData.layout === 'grid'}>
182
+ {#each Object.entries(contentData.value) as [key, value]}
183
+ <div class="stat-item">
184
+ <span class="stat-label">{key}</span>
185
+ <span class="stat-value">{value}</span>
186
+ </div>
187
+ {/each}
188
+ </div>
189
+ {:else if contentData.type === 'status'}
190
+ <div class="status-content">
191
+ {#each Object.entries(contentData.value) as [key, { value, status }]}
192
+ <div class="status-item">
193
+ <span class="status-indicator" style="background: {getStatusColor(status)}"></span>
194
+ <span class="status-label">{key}</span>
195
+ <span class="status-value">{value}</span>
196
+ </div>
197
+ {/each}
198
+ </div>
199
+ {:else if contentData.type === 'table'}
200
+ <div class="table-content">
201
+ <table>
202
+ <thead>
203
+ <tr>
204
+ {#each contentData.value.headers as header}
205
+ <th>{header}</th>
206
+ {/each}
207
+ </tr>
208
+ </thead>
209
+ <tbody>
210
+ {#each contentData.value.rows as row}
211
+ <tr>
212
+ {#each row as cell}
213
+ <td>{cell}</td>
214
+ {/each}
215
+ </tr>
216
+ {/each}
217
+ </tbody>
218
+ </table>
219
+ </div>
220
+ {:else if contentData.type === 'keyvalue'}
221
+ <div class="keyvalue-content" style="grid-template-columns: repeat({contentData.columns || 2}, 1fr)">
222
+ {#each Object.entries(contentData.value) as [key, value]}
223
+ <div class="kv-item">
224
+ <span class="kv-key">{key}:</span>
225
+ <span class="kv-value">{value}</span>
226
+ </div>
227
+ {/each}
228
+ </div>
229
+ {:else if contentData.type === 'custom'}
230
+ <div class="custom-content {contentData.class || ''}">
231
+ {contentData.value}
232
+ </div>
233
+ {/if}
234
+ </div>
235
+ </div>
236
+ {/if}
237
+ </div>
238
+ {/each}
239
+ </div>
240
+
241
+ <!-- Right Panel (optional) -->
242
+ {#if rightPanel}
243
+ <div class="side-panel right-panel">
244
+ {@render rightPanel()}
245
+ </div>
246
+ {/if}
247
+ </div>
248
+
249
+ <!-- Bottom Panel (optional) -->
250
+ {#if bottomPanel}
251
+ <div class="bottom-panel">
252
+ {@render bottomPanel()}
253
+ </div>
254
+ {/if}
255
+
256
+ <!-- Input Area -->
257
+ <form class="input-area" onsubmit={handleSubmit}>
258
+ <div class="input-wrapper">
259
+ <span class="input-prompt">›</span>
260
+ <input
261
+ bind:this={inputElement}
262
+ bind:value={inputValue}
263
+ type="text"
264
+ class="system-input"
265
+ placeholder={processing ? 'AWAITING SYSTEM RESPONSE' : placeholder}
266
+ disabled={processing}
267
+ onkeydown={handleKeyDown}
268
+ autocomplete="off"
269
+ spellcheck="false"
270
+ />
271
+ <button
272
+ type="submit"
273
+ class="submit-indicator"
274
+ disabled={!inputValue.trim() || processing}
275
+ aria-label="Submit"
276
+ >
277
+ <span class="submit-icon">→</span>
278
+ </button>
279
+ </div>
280
+ </form>
281
+ </div>
282
+
283
+ <style>
284
+ .system-interface {
285
+ display: flex;
286
+ flex-direction: column;
287
+ background: linear-gradient(
288
+ 180deg,
289
+ rgba(10, 10, 12, 0.98) 0%,
290
+ rgba(5, 5, 8, 0.98) 100%
291
+ );
292
+ border: 1px solid var(--color-border);
293
+ border-radius: var(--radius-lg);
294
+ overflow: hidden;
295
+ font-family: var(--font-mono);
296
+ box-shadow:
297
+ 0 0 0 1px rgba(255, 255, 255, 0.02),
298
+ 0 20px 60px rgba(0, 0, 0, 0.9),
299
+ inset 0 1px 0 rgba(255, 255, 255, 0.03);
300
+ position: relative;
301
+ backdrop-filter: blur(20px);
302
+ }
303
+
304
+ /* Header */
305
+ .interface-header {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 1rem;
309
+ padding: 1rem 1.5rem;
310
+ background: linear-gradient(
311
+ 180deg,
312
+ rgba(15, 15, 20, 0.8) 0%,
313
+ rgba(10, 10, 15, 0.6) 100%
314
+ );
315
+ border-bottom: 1px solid var(--color-border);
316
+ position: relative;
317
+ }
318
+
319
+ .header-line {
320
+ flex: 1;
321
+ height: 1px;
322
+ background: linear-gradient(
323
+ 90deg,
324
+ transparent 0%,
325
+ var(--color-accent-overlay-20) 50%,
326
+ transparent 100%
327
+ );
328
+ }
329
+
330
+ .header-title {
331
+ display: flex;
332
+ align-items: center;
333
+ gap: 1rem;
334
+ font-size: 0.75rem;
335
+ letter-spacing: 0.15em;
336
+ font-weight: 600;
337
+ }
338
+
339
+ .title-text {
340
+ color: var(--color-accent-soft);
341
+ text-shadow: 0 0 20px var(--color-accent-overlay-30);
342
+ }
343
+
344
+ .processing-indicator {
345
+ color: var(--color-accent);
346
+ font-size: 0.625rem;
347
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
348
+ min-width: 5rem;
349
+ text-align: left;
350
+ }
351
+
352
+ @keyframes pulse {
353
+ 0%,
354
+ 100% {
355
+ opacity: 0.5;
356
+ }
357
+ 50% {
358
+ opacity: 1;
359
+ }
360
+ }
361
+
362
+ /* Top Panel */
363
+ .top-panel {
364
+ padding: 1rem 1.5rem;
365
+ background: rgba(0, 0, 0, 0.2);
366
+ border-bottom: 1px solid var(--color-border);
367
+ }
368
+
369
+ /* Content Area with optional side panels */
370
+ .interface-content {
371
+ flex: 1;
372
+ display: flex;
373
+ overflow: hidden;
374
+ }
375
+
376
+ .side-panel {
377
+ width: 250px;
378
+ padding: 1rem;
379
+ background: rgba(0, 0, 0, 0.3);
380
+ overflow-y: auto;
381
+ overflow-x: hidden;
382
+ }
383
+
384
+ .left-panel {
385
+ border-right: 1px solid var(--color-border);
386
+ }
387
+
388
+ .right-panel {
389
+ border-left: 1px solid var(--color-border);
390
+ }
391
+
392
+ /* Bottom Panel */
393
+ .bottom-panel {
394
+ padding: 1rem 1.5rem;
395
+ background: rgba(0, 0, 0, 0.2);
396
+ border-top: 1px solid var(--color-border);
397
+ }
398
+
399
+ /* Message Stream */
400
+ .message-stream {
401
+ flex: 1;
402
+ overflow-y: auto;
403
+ overflow-x: hidden;
404
+ padding: 1.5rem;
405
+ background: rgba(0, 0, 0, 0.3);
406
+ position: relative;
407
+ }
408
+
409
+ .message-wrapper {
410
+ margin-bottom: 1.5rem;
411
+ opacity: 0;
412
+ transform: translateY(8px);
413
+ transition:
414
+ opacity 0.4s var(--ease-luxe),
415
+ transform 0.4s var(--ease-luxe);
416
+ }
417
+
418
+ .message-wrapper.visible {
419
+ opacity: 1;
420
+ transform: translateY(0);
421
+ }
422
+
423
+ .message-wrapper.updateable {
424
+ /* Messages that can be updated in place might have different styling */
425
+ position: relative;
426
+ }
427
+
428
+ /* Message Meta */
429
+ .message-meta {
430
+ display: flex;
431
+ align-items: center;
432
+ gap: 0.75rem;
433
+ margin-bottom: 0.5rem;
434
+ font-size: 0.625rem;
435
+ letter-spacing: 0.1em;
436
+ }
437
+
438
+ .message-role {
439
+ color: var(--color-text-muted);
440
+ font-weight: 600;
441
+ }
442
+
443
+ .tier-indicator,
444
+ .content-type {
445
+ color: var(--color-accent-soft);
446
+ opacity: 0.6;
447
+ font-size: 0.55rem;
448
+ }
449
+
450
+ .message-timestamp {
451
+ color: var(--color-text-muted);
452
+ opacity: 0.4;
453
+ margin-left: auto;
454
+ }
455
+
456
+ /* User Messages */
457
+ .user-message {
458
+ max-width: 80%;
459
+ }
460
+
461
+ .user-content {
462
+ background: rgba(255, 255, 255, 0.02);
463
+ border: 1px solid var(--color-border);
464
+ border-radius: var(--radius-md);
465
+ padding: 0.75rem 1rem;
466
+ color: var(--color-text);
467
+ line-height: 1.6;
468
+ font-size: var(--text-sm);
469
+ }
470
+
471
+ /* System Messages */
472
+ .system-message {
473
+ border-left: 2px solid;
474
+ padding-left: 1rem;
475
+ transition: all 0.3s var(--ease-luxe);
476
+ }
477
+
478
+ .system-content {
479
+ color: inherit;
480
+ line-height: 1.7;
481
+ font-size: var(--text-sm);
482
+ }
483
+
484
+ /* Content Type Renderers */
485
+ .text-content {
486
+ white-space: pre-wrap;
487
+ word-wrap: break-word;
488
+ }
489
+
490
+ .stats-content {
491
+ display: flex;
492
+ flex-direction: column;
493
+ gap: 0.75rem;
494
+ }
495
+
496
+ .stats-content.grid-layout {
497
+ display: grid;
498
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
499
+ gap: 1rem;
500
+ }
501
+
502
+ .stat-item {
503
+ display: flex;
504
+ flex-direction: column;
505
+ gap: 0.25rem;
506
+ padding: 0.75rem;
507
+ background: rgba(0, 0, 0, 0.3);
508
+ border: 1px solid var(--color-border);
509
+ border-radius: var(--radius-sm);
510
+ }
511
+
512
+ .stat-label {
513
+ font-size: 0.625rem;
514
+ text-transform: uppercase;
515
+ letter-spacing: 0.1em;
516
+ opacity: 0.6;
517
+ }
518
+
519
+ .stat-value {
520
+ font-size: 1.5rem;
521
+ font-weight: 700;
522
+ text-shadow: 0 0 20px currentColor;
523
+ }
524
+
525
+ .status-content {
526
+ display: flex;
527
+ flex-direction: column;
528
+ gap: 0.5rem;
529
+ }
530
+
531
+ .status-item {
532
+ display: flex;
533
+ align-items: center;
534
+ gap: 0.75rem;
535
+ padding: 0.5rem 0.75rem;
536
+ background: rgba(0, 0, 0, 0.2);
537
+ border-radius: var(--radius-sm);
538
+ }
539
+
540
+ .status-indicator {
541
+ width: 8px;
542
+ height: 8px;
543
+ border-radius: 50%;
544
+ box-shadow: 0 0 10px currentColor;
545
+ flex-shrink: 0;
546
+ }
547
+
548
+ .status-label {
549
+ flex: 1;
550
+ font-size: 0.75rem;
551
+ opacity: 0.8;
552
+ }
553
+
554
+ .status-value {
555
+ font-size: 0.875rem;
556
+ font-weight: 600;
557
+ }
558
+
559
+ .table-content {
560
+ overflow-x: auto;
561
+ }
562
+
563
+ .table-content table {
564
+ width: 100%;
565
+ border-collapse: collapse;
566
+ font-size: 0.75rem;
567
+ }
568
+
569
+ .table-content th {
570
+ text-align: left;
571
+ padding: 0.5rem 0.75rem;
572
+ border-bottom: 1px solid var(--color-border);
573
+ font-weight: 600;
574
+ text-transform: uppercase;
575
+ letter-spacing: 0.05em;
576
+ font-size: 0.625rem;
577
+ opacity: 0.8;
578
+ }
579
+
580
+ .table-content td {
581
+ padding: 0.5rem 0.75rem;
582
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
583
+ }
584
+
585
+ .keyvalue-content {
586
+ display: grid;
587
+ gap: 0.5rem;
588
+ }
589
+
590
+ .kv-item {
591
+ display: flex;
592
+ gap: 0.5rem;
593
+ padding: 0.375rem 0.5rem;
594
+ background: rgba(0, 0, 0, 0.2);
595
+ border-radius: var(--radius-sm);
596
+ font-size: 0.75rem;
597
+ }
598
+
599
+ .kv-key {
600
+ opacity: 0.7;
601
+ font-weight: 600;
602
+ }
603
+
604
+ .kv-value {
605
+ flex: 1;
606
+ }
607
+
608
+ .custom-content {
609
+ /* Allow custom styling via class */
610
+ }
611
+
612
+ /* Input Area */
613
+ .input-area {
614
+ background: linear-gradient(
615
+ 180deg,
616
+ rgba(10, 10, 15, 0.6) 0%,
617
+ rgba(15, 15, 20, 0.8) 100%
618
+ );
619
+ border-top: 1px solid var(--color-border);
620
+ padding: 1rem 1.5rem;
621
+ position: relative;
622
+ }
623
+
624
+ .input-wrapper {
625
+ display: flex;
626
+ align-items: center;
627
+ gap: 0.75rem;
628
+ background: rgba(0, 0, 0, 0.4);
629
+ border: 1px solid var(--color-border);
630
+ border-radius: var(--radius-md);
631
+ padding: 0.75rem 1rem;
632
+ transition: all 0.3s var(--ease-luxe);
633
+ }
634
+
635
+ .input-wrapper:focus-within {
636
+ border-color: var(--color-accent-overlay-50);
637
+ box-shadow: 0 0 20px var(--color-accent-overlay-20);
638
+ }
639
+
640
+ .input-prompt {
641
+ color: var(--color-accent);
642
+ font-size: 1rem;
643
+ font-weight: 700;
644
+ user-select: none;
645
+ text-shadow: 0 0 10px currentColor;
646
+ flex-shrink: 0;
647
+ }
648
+
649
+ .system-input {
650
+ flex: 1;
651
+ background: transparent;
652
+ border: none;
653
+ color: var(--color-text);
654
+ font-family: var(--font-mono);
655
+ font-size: var(--text-sm);
656
+ outline: none;
657
+ letter-spacing: 0.02em;
658
+ caret-color: var(--color-accent);
659
+ }
660
+
661
+ .system-input::placeholder {
662
+ color: var(--color-text-muted);
663
+ opacity: 0.3;
664
+ letter-spacing: 0.05em;
665
+ font-size: 0.75rem;
666
+ }
667
+
668
+ .system-input:disabled {
669
+ opacity: 0.4;
670
+ cursor: not-allowed;
671
+ }
672
+
673
+ .submit-indicator {
674
+ background: transparent;
675
+ border: none;
676
+ color: var(--color-accent-soft);
677
+ font-size: 1.25rem;
678
+ cursor: pointer;
679
+ padding: 0;
680
+ transition: all 0.3s var(--ease-luxe);
681
+ opacity: 0.3;
682
+ flex-shrink: 0;
683
+ }
684
+
685
+ .submit-indicator:not(:disabled) {
686
+ opacity: 1;
687
+ }
688
+
689
+ .submit-indicator:not(:disabled):hover {
690
+ color: var(--color-accent);
691
+ text-shadow: 0 0 12px currentColor;
692
+ transform: translateX(2px);
693
+ }
694
+
695
+ .submit-indicator:disabled {
696
+ cursor: not-allowed;
697
+ opacity: 0.2;
698
+ }
699
+
700
+ .submit-icon {
701
+ display: block;
702
+ line-height: 1;
703
+ }
704
+
705
+ /* Scrollbar */
706
+ .message-stream::-webkit-scrollbar,
707
+ .side-panel::-webkit-scrollbar {
708
+ width: 0.375rem;
709
+ }
710
+
711
+ .message-stream::-webkit-scrollbar-track,
712
+ .side-panel::-webkit-scrollbar-track {
713
+ background: rgba(0, 0, 0, 0.4);
714
+ }
715
+
716
+ .message-stream::-webkit-scrollbar-thumb,
717
+ .side-panel::-webkit-scrollbar-thumb {
718
+ background: var(--color-accent-overlay-20);
719
+ border-radius: var(--radius-sm);
720
+ transition: background 0.3s var(--ease-luxe);
721
+ }
722
+
723
+ .message-stream::-webkit-scrollbar-thumb:hover,
724
+ .side-panel::-webkit-scrollbar-thumb:hover {
725
+ background: var(--color-accent-overlay-40);
726
+ }</style>