@aparte/core 0.2.0-alpha.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.
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/client/aparte-client.d.ts +326 -0
- package/dist/client/aparte-client.d.ts.map +1 -0
- package/dist/client/stream-adapter.d.ts +197 -0
- package/dist/client/stream-adapter.d.ts.map +1 -0
- package/dist/components/bubble/aparte-chat-bubble.d.ts +153 -0
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -0
- package/dist/components/bubble/bubble-sync.d.ts +44 -0
- package/dist/components/bubble/bubble-sync.d.ts.map +1 -0
- package/dist/components/bubble/index.d.ts +4 -0
- package/dist/components/bubble/index.d.ts.map +1 -0
- package/dist/components/chat/aparte-chat.d.ts +49 -0
- package/dist/components/chat/aparte-chat.d.ts.map +1 -0
- package/dist/components/chat/index.d.ts +2 -0
- package/dist/components/chat/index.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-action.d.ts +37 -0
- package/dist/components/composer/aparte-composer-action.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-add-attachment.d.ts +27 -0
- package/dist/components/composer/aparte-composer-add-attachment.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-attachments.d.ts +26 -0
- package/dist/components/composer/aparte-composer-attachments.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-cancel.d.ts +21 -0
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-input.d.ts +63 -0
- package/dist/components/composer/aparte-composer-input.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer-send.d.ts +25 -0
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -0
- package/dist/components/composer/aparte-composer.d.ts +150 -0
- package/dist/components/composer/aparte-composer.d.ts.map +1 -0
- package/dist/components/composer/index.d.ts +9 -0
- package/dist/components/composer/index.d.ts.map +1 -0
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +50 -0
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -0
- package/dist/components/conversation-list/index.d.ts +2 -0
- package/dist/components/conversation-list/index.d.ts.map +1 -0
- package/dist/components/elicitation/aparte-elicitation.d.ts +29 -0
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/status/aparte-chat-status.d.ts +34 -0
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -0
- package/dist/components/status/index.d.ts +2 -0
- package/dist/components/status/index.d.ts.map +1 -0
- package/dist/components/viewport/aparte-chat-viewport.d.ts +358 -0
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -0
- package/dist/components/viewport/index.d.ts +2 -0
- package/dist/components/viewport/index.d.ts.map +1 -0
- package/dist/config/action-provider.d.ts +59 -0
- package/dist/config/action-provider.d.ts.map +1 -0
- package/dist/config/aparte-config.d.ts +490 -0
- package/dist/config/aparte-config.d.ts.map +1 -0
- package/dist/config/attachment-renderer.d.ts +28 -0
- package/dist/config/attachment-renderer.d.ts.map +1 -0
- package/dist/config/avatar-provider.d.ts +35 -0
- package/dist/config/avatar-provider.d.ts.map +1 -0
- package/dist/config/bubble-shell-renderer.d.ts +41 -0
- package/dist/config/bubble-shell-renderer.d.ts.map +1 -0
- package/dist/config/config-context.d.ts +47 -0
- package/dist/config/config-context.d.ts.map +1 -0
- package/dist/config/error-renderer.d.ts +26 -0
- package/dist/config/error-renderer.d.ts.map +1 -0
- package/dist/config/icon-provider.d.ts +63 -0
- package/dist/config/icon-provider.d.ts.map +1 -0
- package/dist/config/index.d.ts +19 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/locale.d.ts +60 -0
- package/dist/config/locale.d.ts.map +1 -0
- package/dist/config/sanitize.d.ts +31 -0
- package/dist/config/sanitize.d.ts.map +1 -0
- package/dist/config/sibling-nav-renderer.d.ts +27 -0
- package/dist/config/sibling-nav-renderer.d.ts.map +1 -0
- package/dist/config/skeleton-provider.d.ts +26 -0
- package/dist/config/skeleton-provider.d.ts.map +1 -0
- package/dist/config/status-renderer.d.ts +23 -0
- package/dist/config/status-renderer.d.ts.map +1 -0
- package/dist/conversations/conversation-controller.d.ts +126 -0
- package/dist/conversations/conversation-controller.d.ts.map +1 -0
- package/dist/conversations/conversation-manager.d.ts +98 -0
- package/dist/conversations/conversation-manager.d.ts.map +1 -0
- package/dist/conversations/index.d.ts +5 -0
- package/dist/conversations/index.d.ts.map +1 -0
- package/dist/conversations/types.d.ts +172 -0
- package/dist/conversations/types.d.ts.map +1 -0
- package/dist/custom-elements.json +15833 -0
- package/dist/elicitation/index.d.ts +20 -0
- package/dist/elicitation/index.d.ts.map +1 -0
- package/dist/elicitation/panel.d.ts +18 -0
- package/dist/elicitation/panel.d.ts.map +1 -0
- package/dist/elicitation/types.d.ts +98 -0
- package/dist/elicitation/types.d.ts.map +1 -0
- package/dist/host/aparte-chat-host.d.ts +176 -0
- package/dist/host/aparte-chat-host.d.ts.map +1 -0
- package/dist/host/index.d.ts +2 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/index-D89k-n2Q.js +6294 -0
- package/dist/index-D89k-n2Q.js.map +1 -0
- package/dist/index.css +2554 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3763 -0
- package/dist/index.js.map +1 -0
- package/dist/index.node.d.ts +53 -0
- package/dist/index.node.d.ts.map +1 -0
- package/dist/index.node.js +49 -0
- package/dist/index.node.js.map +1 -0
- package/dist/interop/element-props.d.ts +23 -0
- package/dist/interop/element-props.d.ts.map +1 -0
- package/dist/parsers/aparte-event-stream.d.ts +13 -0
- package/dist/parsers/aparte-event-stream.d.ts.map +1 -0
- package/dist/parsers/aparte-stream-parser.d.ts +137 -0
- package/dist/parsers/aparte-stream-parser.d.ts.map +1 -0
- package/dist/parsers/index.d.ts +4 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +8 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts +25 -0
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts.map +1 -0
- package/dist/primitives/progress-spinner/index.d.ts +2 -0
- package/dist/primitives/progress-spinner/index.d.ts.map +1 -0
- package/dist/primitives/select/aparte-optgroup.d.ts +32 -0
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -0
- package/dist/primitives/select/aparte-option.d.ts +30 -0
- package/dist/primitives/select/aparte-option.d.ts.map +1 -0
- package/dist/primitives/select/aparte-select.d.ts +74 -0
- package/dist/primitives/select/aparte-select.d.ts.map +1 -0
- package/dist/primitives/select/index.d.ts +9 -0
- package/dist/primitives/select/index.d.ts.map +1 -0
- package/dist/renderers/index.d.ts +5 -0
- package/dist/renderers/index.d.ts.map +1 -0
- package/dist/renderers/segment-renderers.d.ts +31 -0
- package/dist/renderers/segment-renderers.d.ts.map +1 -0
- package/dist/runtime/message-repository.d.ts +111 -0
- package/dist/runtime/message-repository.d.ts.map +1 -0
- package/dist/transport/backend-handler.d.ts +50 -0
- package/dist/transport/backend-handler.d.ts.map +1 -0
- package/dist/transport/backend-transport.d.ts +39 -0
- package/dist/transport/backend-transport.d.ts.map +1 -0
- package/dist/transport/direct-transport.d.ts +36 -0
- package/dist/transport/direct-transport.d.ts.map +1 -0
- package/dist/transport/index.d.ts +6 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/types.d.ts +73 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/types/chat.d.ts +223 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/errors.d.ts +25 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/event-map.d.ts +41 -0
- package/dist/types/event-map.d.ts.map +1 -0
- package/dist/types/events.d.ts +290 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/imperative-api.d.ts +38 -0
- package/dist/types/imperative-api.d.ts.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/model-provider.d.ts +229 -0
- package/dist/types/model-provider.d.ts.map +1 -0
- package/dist/types/models.d.ts +173 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/parsers.d.ts +42 -0
- package/dist/types/parsers.d.ts.map +1 -0
- package/dist/types/providers.d.ts +93 -0
- package/dist/types/providers.d.ts.map +1 -0
- package/dist/types/segments.d.ts +221 -0
- package/dist/types/segments.d.ts.map +1 -0
- package/dist/types/theming.d.ts +44 -0
- package/dist/types/theming.d.ts.map +1 -0
- package/dist/types/tools.d.ts +98 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/utils/assert-never.d.ts +9 -0
- package/dist/utils/assert-never.d.ts.map +1 -0
- package/dist/utils/css-escape.d.ts +15 -0
- package/dist/utils/css-escape.d.ts.map +1 -0
- package/package.json +68 -0
package/dist/index.css
ADDED
|
@@ -0,0 +1,2554 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Aparte CSS
|
|
3
|
+
* Single source of truth for all component styles.
|
|
4
|
+
* Theme is controlled via CSS variables - app sets [data-aparte-theme="dark"] to switch.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* =========================================
|
|
8
|
+
Light Theme (Default)
|
|
9
|
+
========================================= */
|
|
10
|
+
:root,
|
|
11
|
+
:host {
|
|
12
|
+
/* Base Colors */
|
|
13
|
+
--aparte-primary: #b07d33;
|
|
14
|
+
--aparte-primary-hover: #a06f28;
|
|
15
|
+
--aparte-secondary: #9a8fb0;
|
|
16
|
+
--aparte-neutral: #6d6479;
|
|
17
|
+
|
|
18
|
+
/* Backgrounds & Surfaces */
|
|
19
|
+
--aparte-bg: #f6f2ea;
|
|
20
|
+
--aparte-surface-1: #fffdf8;
|
|
21
|
+
/* Bubbles, cards */
|
|
22
|
+
--aparte-surface-2: #f1ebdf;
|
|
23
|
+
/* Code blocks, headers */
|
|
24
|
+
--aparte-surface-3: #e7dfce;
|
|
25
|
+
/* Skeletons, disabled */
|
|
26
|
+
|
|
27
|
+
/* Text */
|
|
28
|
+
--aparte-text: #241f2b;
|
|
29
|
+
--aparte-text-muted: #6d6479;
|
|
30
|
+
--aparte-text-inverse: #fffdf8;
|
|
31
|
+
|
|
32
|
+
/* Borders */
|
|
33
|
+
--aparte-border: #e5ddce;
|
|
34
|
+
--aparte-border-focus: var(--aparte-primary);
|
|
35
|
+
--aparte-border-width: 1px;
|
|
36
|
+
|
|
37
|
+
/* Status Colors */
|
|
38
|
+
--aparte-info: #3b82f6;
|
|
39
|
+
--aparte-success: #10b981;
|
|
40
|
+
--aparte-warning: #f59e0b;
|
|
41
|
+
--aparte-error: #ef4444;
|
|
42
|
+
|
|
43
|
+
/* Radius scale */
|
|
44
|
+
--aparte-radius-xs: 2px;
|
|
45
|
+
--aparte-radius-sm: 4px;
|
|
46
|
+
--aparte-radius-md: 6px;
|
|
47
|
+
--aparte-radius-lg: 8px;
|
|
48
|
+
--aparte-radius-xl: 12px;
|
|
49
|
+
--aparte-radius-full: 9999px;
|
|
50
|
+
|
|
51
|
+
/* Component-specific radius (overridable per app) */
|
|
52
|
+
--aparte-radius-input: var(--aparte-radius-lg);
|
|
53
|
+
--aparte-radius-input-footer: var(--aparte-radius-lg);
|
|
54
|
+
--aparte-radius-send-btn: var(--aparte-radius-md);
|
|
55
|
+
--aparte-radius-action-btn: var(--aparte-radius-sm);
|
|
56
|
+
--aparte-radius-select: var(--aparte-radius-md);
|
|
57
|
+
--aparte-radius-avatar: var(--aparte-radius-md);
|
|
58
|
+
--aparte-radius-bubble: var(--aparte-radius-lg);
|
|
59
|
+
--aparte-radius-code: var(--aparte-radius-lg);
|
|
60
|
+
--aparte-radius-thinking: var(--aparte-radius-lg);
|
|
61
|
+
--aparte-radius-terminal: var(--aparte-radius-lg);
|
|
62
|
+
--aparte-radius-error: var(--aparte-radius-md);
|
|
63
|
+
--aparte-radius-file-tree: var(--aparte-radius-lg);
|
|
64
|
+
|
|
65
|
+
/* Spacing scale — every gap / padding / margin / offset routes through these,
|
|
66
|
+
so there are no raw px spacings in the rules. Incidental, pixel-tuned values
|
|
67
|
+
(e.g. an overlay inset) get their own component var instead of a scale step. */
|
|
68
|
+
--aparte-space-1: 2px;
|
|
69
|
+
--aparte-space-2: 4px;
|
|
70
|
+
--aparte-space-3: 6px;
|
|
71
|
+
--aparte-space-4: 8px;
|
|
72
|
+
--aparte-space-5: 10px;
|
|
73
|
+
--aparte-space-6: 12px;
|
|
74
|
+
--aparte-space-7: 14px;
|
|
75
|
+
--aparte-space-8: 16px;
|
|
76
|
+
|
|
77
|
+
/* Font-size scale — component text sizes reference these (no raw px sizes). */
|
|
78
|
+
--aparte-font-size-2xs: 10px;
|
|
79
|
+
--aparte-font-size-xs: 11px;
|
|
80
|
+
--aparte-font-size-sm: 12px;
|
|
81
|
+
--aparte-font-size-md: 13px;
|
|
82
|
+
--aparte-font-size-lg: 14px;
|
|
83
|
+
--aparte-font-size-base: 15px;
|
|
84
|
+
|
|
85
|
+
/* Font-weight scale — every font-weight references these (no raw weights). */
|
|
86
|
+
--aparte-font-weight-normal: 400;
|
|
87
|
+
--aparte-font-weight-medium: 500;
|
|
88
|
+
--aparte-font-weight-semibold: 600;
|
|
89
|
+
--aparte-font-weight-bold: 700;
|
|
90
|
+
|
|
91
|
+
/* Line-height scale — every line-height references these (no raw values). */
|
|
92
|
+
--aparte-line-height-none: 1;
|
|
93
|
+
--aparte-line-height-tight: 1.25;
|
|
94
|
+
--aparte-line-height-normal: 1.5;
|
|
95
|
+
--aparte-line-height-relaxed: 1.6;
|
|
96
|
+
--aparte-line-height-loose: 1.7;
|
|
97
|
+
|
|
98
|
+
/* Typography */
|
|
99
|
+
--aparte-font-family: system-ui, -apple-system, sans-serif;
|
|
100
|
+
|
|
101
|
+
/* Text/icon over a --aparte-primary (brass) fill — send button, run button. */
|
|
102
|
+
--aparte-on-primary: #ffffff;
|
|
103
|
+
/* Focus ring — derived from the accent so it themes automatically. */
|
|
104
|
+
--aparte-focus-ring: 0 0 0 3px color-mix(in srgb, var(--aparte-primary) 15%, transparent);
|
|
105
|
+
/* Outline width for keyboard focus + drag-over indicators. */
|
|
106
|
+
--aparte-focus-outline-width: 2px;
|
|
107
|
+
/* Scrollbars rendered by the library. */
|
|
108
|
+
--aparte-scrollbar-width: 6px;
|
|
109
|
+
/* Comfortable hit-area on coarse (touch) pointers. */
|
|
110
|
+
--aparte-touch-target-size: 44px;
|
|
111
|
+
|
|
112
|
+
/* Messages */
|
|
113
|
+
--aparte-message-gap: 12px;
|
|
114
|
+
--aparte-message-padding: 16px 12px;
|
|
115
|
+
--aparte-message-max-width: 800px;
|
|
116
|
+
|
|
117
|
+
/* Bubbles — opt-in. By default both roles render as a transparent row with
|
|
118
|
+
no bubble background; consumers can flip these to get a chat-app look. */
|
|
119
|
+
--aparte-message-content-bg-user: #efe7f6;
|
|
120
|
+
--aparte-message-content-bg-assistant: transparent;
|
|
121
|
+
--aparte-message-content-text-user: var(--aparte-text);
|
|
122
|
+
--aparte-message-content-text-assistant: var(--aparte-text);
|
|
123
|
+
--aparte-message-content-padding: 10px 14px;
|
|
124
|
+
--aparte-message-content-radius: 14px;
|
|
125
|
+
|
|
126
|
+
/* Aliases used by some segment renderers (artifact card, tool pill).
|
|
127
|
+
Mapped to existing tokens so consumers that override --aparte-surface-1/2
|
|
128
|
+
get cohesive results without touching every rule. */
|
|
129
|
+
--aparte-surface: var(--aparte-surface-1);
|
|
130
|
+
--aparte-surface-hover: var(--aparte-surface-2);
|
|
131
|
+
--aparte-text-secondary: var(--aparte-text-muted);
|
|
132
|
+
--aparte-accent: var(--aparte-primary);
|
|
133
|
+
--aparte-success-border: var(--aparte-success);
|
|
134
|
+
--aparte-success-surface: color-mix(in oklch, var(--aparte-success) 12%, transparent);
|
|
135
|
+
--aparte-error-border-soft: var(--aparte-error);
|
|
136
|
+
--aparte-error-surface: color-mix(in oklch, var(--aparte-error) 12%, transparent);
|
|
137
|
+
|
|
138
|
+
/* Code typography — exposed so apps can swap in Geist Mono / Cascadia / … */
|
|
139
|
+
--aparte-code-font-family: ui-monospace, 'Cascadia Code', 'JetBrains Mono', 'Geist Mono', SFMono-Regular, Consolas, 'Liberation Mono', monospace;
|
|
140
|
+
|
|
141
|
+
/* Attachments */
|
|
142
|
+
--aparte-attachment-chip-bg: var(--aparte-surface-2);
|
|
143
|
+
--aparte-attachment-chip-border: var(--aparte-border);
|
|
144
|
+
--aparte-attachment-chip-radius: var(--aparte-radius-sm);
|
|
145
|
+
--aparte-attachment-chip-color: var(--aparte-text);
|
|
146
|
+
--aparte-attachment-image-size: 72px;
|
|
147
|
+
--aparte-attachments-max-height: 140px;
|
|
148
|
+
|
|
149
|
+
/* Attachment thumbnail tile (composer preview + sent-message strip) */
|
|
150
|
+
--aparte-thumb-radius: var(--aparte-radius-lg);
|
|
151
|
+
--aparte-thumb-name-color: #ffffff;
|
|
152
|
+
--aparte-thumb-name-scrim: linear-gradient(to top, rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0));
|
|
153
|
+
--aparte-thumb-name-padding: 14px 5px 4px;
|
|
154
|
+
--aparte-thumb-remove-size: 18px;
|
|
155
|
+
--aparte-thumb-remove-inset: 3px;
|
|
156
|
+
--aparte-thumb-remove-bg: rgba(0, 0, 0, 0.6);
|
|
157
|
+
--aparte-thumb-remove-bg-hover: rgba(0, 0, 0, 0.85);
|
|
158
|
+
--aparte-thumb-remove-color: #ffffff;
|
|
159
|
+
|
|
160
|
+
/* Action Bar */
|
|
161
|
+
--aparte-action-bar-gap: 4px;
|
|
162
|
+
--aparte-action-bar-btn-size: 28px;
|
|
163
|
+
--aparte-action-bar-btn-color: var(--aparte-text-muted);
|
|
164
|
+
--aparte-action-bar-btn-hover-bg: var(--aparte-surface-2);
|
|
165
|
+
--aparte-action-bar-btn-hover-color: var(--aparte-text);
|
|
166
|
+
|
|
167
|
+
/* Branch Picker */
|
|
168
|
+
--aparte-branch-picker-gap: 4px;
|
|
169
|
+
--aparte-branch-picker-btn-size: 20px;
|
|
170
|
+
--aparte-branch-picker-btn-icon-size: 16px;
|
|
171
|
+
--aparte-branch-picker-btn-color: var(--aparte-text-muted);
|
|
172
|
+
--aparte-branch-picker-btn-hover-color: var(--aparte-text);
|
|
173
|
+
--aparte-branch-picker-label-size: 12px;
|
|
174
|
+
--aparte-branch-picker-label-color: var(--aparte-text-muted);
|
|
175
|
+
--aparte-branch-picker-label-min-width: 32px;
|
|
176
|
+
|
|
177
|
+
/* Avatars */
|
|
178
|
+
--aparte-avatar-size: 32px;
|
|
179
|
+
--aparte-avatar-font-size: 14px;
|
|
180
|
+
--aparte-avatar-radius: var(--aparte-radius-avatar);
|
|
181
|
+
--aparte-avatar-bg-user: var(--aparte-primary);
|
|
182
|
+
--aparte-avatar-text-user: var(--aparte-text-inverse);
|
|
183
|
+
--aparte-avatar-bg-assistant: var(--aparte-surface-3);
|
|
184
|
+
--aparte-avatar-text-assistant: var(--aparte-text-inverse);
|
|
185
|
+
--aparte-avatar-image-user: none;
|
|
186
|
+
--aparte-avatar-image-assistant: none;
|
|
187
|
+
--aparte-avatar-image-size: 90%;
|
|
188
|
+
|
|
189
|
+
/* Text Sizes */
|
|
190
|
+
--aparte-name-font-size: 14px;
|
|
191
|
+
--aparte-name-color: var(--aparte-text);
|
|
192
|
+
--aparte-timestamp-font-size: 12px;
|
|
193
|
+
--aparte-timestamp-color: var(--aparte-text-muted);
|
|
194
|
+
--aparte-content-font-size: 15px;
|
|
195
|
+
--aparte-content-color: var(--aparte-text);
|
|
196
|
+
|
|
197
|
+
/* Input */
|
|
198
|
+
--aparte-input-bg: var(--aparte-surface-1);
|
|
199
|
+
--aparte-input-border: var(--aparte-border);
|
|
200
|
+
--aparte-input-text: var(--aparte-text);
|
|
201
|
+
--aparte-input-placeholder: var(--aparte-text-muted);
|
|
202
|
+
--aparte-input-focus-border: var(--aparte-primary);
|
|
203
|
+
--aparte-input-gap: 8px;
|
|
204
|
+
--aparte-input-editor-font-size: 15px;
|
|
205
|
+
--aparte-input-editor-max-height: 200px;
|
|
206
|
+
--aparte-input-container-min-height: 44px;
|
|
207
|
+
|
|
208
|
+
/* Send button + inline action buttons */
|
|
209
|
+
--aparte-send-btn-size: 36px;
|
|
210
|
+
--aparte-input-action-btn-size: 36px;
|
|
211
|
+
--aparte-input-action-btn-icon-size: 20px;
|
|
212
|
+
--aparte-select-min-width: 120px;
|
|
213
|
+
|
|
214
|
+
/* Status Indicator */
|
|
215
|
+
--aparte-status-color: var(--aparte-text-muted);
|
|
216
|
+
--aparte-status-bg: transparent;
|
|
217
|
+
--aparte-status-dot-size: 6px;
|
|
218
|
+
|
|
219
|
+
/* Thinking Segment */
|
|
220
|
+
--aparte-thinking-border: var(--aparte-border);
|
|
221
|
+
--aparte-thinking-bg: var(--aparte-surface-2);
|
|
222
|
+
--aparte-thinking-text: var(--aparte-text-muted);
|
|
223
|
+
--aparte-thinking-content: var(--aparte-text);
|
|
224
|
+
--aparte-thinking-content-bg: var(--aparte-surface-1);
|
|
225
|
+
--aparte-thinking-content-max-height: 300px;
|
|
226
|
+
--aparte-thinking-content-line-height: 1.55;
|
|
227
|
+
--aparte-thinking-toggle-size: 9px;
|
|
228
|
+
--aparte-thinking-rail-width: 2px;
|
|
229
|
+
|
|
230
|
+
/* Code Blocks */
|
|
231
|
+
--aparte-code-bg: var(--aparte-surface-1);
|
|
232
|
+
--aparte-code-header-bg: var(--aparte-surface-2);
|
|
233
|
+
--aparte-code-border: var(--aparte-border);
|
|
234
|
+
--aparte-code-header-text: var(--aparte-text-muted);
|
|
235
|
+
--aparte-code-copy-hover-bg: rgba(0, 0, 0, 0.05);
|
|
236
|
+
--aparte-code-copy-icon-size: 14px;
|
|
237
|
+
--aparte-code-inline-font-size: 0.875em;
|
|
238
|
+
|
|
239
|
+
/* Terminal */
|
|
240
|
+
--aparte-terminal-bg: #1e293b;
|
|
241
|
+
--aparte-terminal-text: #e2e8f0;
|
|
242
|
+
--aparte-terminal-icon: #64748b;
|
|
243
|
+
--aparte-terminal-hover: #334155;
|
|
244
|
+
--aparte-terminal-running: #22c55e;
|
|
245
|
+
--aparte-terminal-output-bg: #0f172a;
|
|
246
|
+
--aparte-terminal-output-text: #94a3b8;
|
|
247
|
+
--aparte-terminal-copy-btn-size: 26px;
|
|
248
|
+
--aparte-terminal-font-size: 13px;
|
|
249
|
+
--aparte-terminal-output-max-height: 200px;
|
|
250
|
+
|
|
251
|
+
/* Progress */
|
|
252
|
+
--aparte-progress-bar-bg: var(--aparte-surface-3);
|
|
253
|
+
--aparte-progress-bar-fill: var(--aparte-primary);
|
|
254
|
+
--aparte-progress-label: var(--aparte-text);
|
|
255
|
+
|
|
256
|
+
/* Scroll-to-bottom button */
|
|
257
|
+
--aparte-scroll-btn-size: 36px;
|
|
258
|
+
--aparte-scroll-btn-bg: var(--aparte-surface-1);
|
|
259
|
+
--aparte-scroll-btn-color: var(--aparte-text);
|
|
260
|
+
--aparte-scroll-btn-border: var(--aparte-border);
|
|
261
|
+
--aparte-scroll-btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
262
|
+
--aparte-scroll-btn-hover-bg: var(--aparte-surface-2);
|
|
263
|
+
|
|
264
|
+
/* File Tree */
|
|
265
|
+
--aparte-file-tree-bg: var(--aparte-surface-1);
|
|
266
|
+
--aparte-file-tree-border: var(--aparte-border);
|
|
267
|
+
--aparte-file-tree-header-bg: var(--aparte-surface-2);
|
|
268
|
+
--aparte-file-tree-hover: var(--aparte-surface-2);
|
|
269
|
+
--aparte-file-tree-title: var(--aparte-text-muted);
|
|
270
|
+
/* Git-status file colours reuse the semantic status tokens by default. */
|
|
271
|
+
--aparte-file-status-added: var(--aparte-success);
|
|
272
|
+
--aparte-file-status-modified: var(--aparte-info);
|
|
273
|
+
--aparte-file-status-deleted: var(--aparte-error);
|
|
274
|
+
|
|
275
|
+
/* Error segment */
|
|
276
|
+
--aparte-error-bg: #fef2f2;
|
|
277
|
+
--aparte-error-border: #fecaca;
|
|
278
|
+
--aparte-error-solid: #dc2626;
|
|
279
|
+
--aparte-error-text: #991b1b;
|
|
280
|
+
--aparte-error-title: #7f1d1d;
|
|
281
|
+
--aparte-error-icon-size: 20px;
|
|
282
|
+
--aparte-error-rail-width: 4px;
|
|
283
|
+
|
|
284
|
+
/* Prose (segment-content) */
|
|
285
|
+
--aparte-prose-p-margin: 0.4em 0;
|
|
286
|
+
--aparte-prose-h1-size: 1.4em;
|
|
287
|
+
--aparte-prose-h2-size: 1.25em;
|
|
288
|
+
--aparte-prose-h3-size: 1.1em;
|
|
289
|
+
--aparte-prose-list-indent: 1.5em;
|
|
290
|
+
--aparte-prose-list-margin: 0.4em 0;
|
|
291
|
+
--aparte-prose-li-margin: 0.15em 0;
|
|
292
|
+
--aparte-prose-blockquote-border: var(--aparte-border);
|
|
293
|
+
--aparte-prose-blockquote-border-width: 3px;
|
|
294
|
+
--aparte-prose-code-bg: var(--aparte-surface-2);
|
|
295
|
+
|
|
296
|
+
/* Viewport */
|
|
297
|
+
--aparte-viewport-padding: 16px;
|
|
298
|
+
|
|
299
|
+
/* Content */
|
|
300
|
+
--aparte-content-line-height: var(--aparte-line-height-loose, 1.7);
|
|
301
|
+
--aparte-cursor-color: var(--aparte-primary);
|
|
302
|
+
|
|
303
|
+
/* Status */
|
|
304
|
+
--aparte-status-font-size: 13px;
|
|
305
|
+
|
|
306
|
+
/* Input (composer) */
|
|
307
|
+
--aparte-input-font-size: 14px;
|
|
308
|
+
--aparte-input-line-height: var(--aparte-line-height-normal, 1.5);
|
|
309
|
+
--aparte-input-padding-x: 12px;
|
|
310
|
+
--aparte-input-padding-y: 10px;
|
|
311
|
+
|
|
312
|
+
/* Conversation List */
|
|
313
|
+
--aparte-conv-list-gap: 2px;
|
|
314
|
+
--aparte-conv-item-padding: 7px 10px;
|
|
315
|
+
--aparte-conv-item-radius: var(--aparte-radius-md);
|
|
316
|
+
--aparte-conv-item-color: var(--aparte-text-muted);
|
|
317
|
+
--aparte-conv-item-color-active: var(--aparte-text);
|
|
318
|
+
--aparte-conv-item-bg-hover: var(--aparte-surface-3);
|
|
319
|
+
--aparte-conv-item-bg-active: var(--aparte-surface-3);
|
|
320
|
+
--aparte-conv-item-font-size: 0.8125rem;
|
|
321
|
+
--aparte-conv-item-font-weight-active: var(--aparte-font-weight-medium, 500);
|
|
322
|
+
--aparte-conv-delete-color: var(--aparte-text-muted);
|
|
323
|
+
--aparte-conv-delete-bg-hover: var(--aparte-error);
|
|
324
|
+
--aparte-conv-delete-color-hover: var(--aparte-text-inverse);
|
|
325
|
+
--aparte-conv-delete-radius: var(--aparte-radius-sm);
|
|
326
|
+
--aparte-conv-item-gap: 6px;
|
|
327
|
+
--aparte-conv-action-btn-size: 20px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* =========================================
|
|
331
|
+
Dark Theme (App-controlled via attribute)
|
|
332
|
+
Usage: <div data-aparte-theme="dark">...</div>
|
|
333
|
+
========================================= */
|
|
334
|
+
[data-aparte-theme="dark"] {
|
|
335
|
+
/* Backgrounds */
|
|
336
|
+
--aparte-bg: #17141c;
|
|
337
|
+
--aparte-surface-1: #211b28;
|
|
338
|
+
--aparte-surface-2: #2a2333;
|
|
339
|
+
--aparte-surface-3: #342a40;
|
|
340
|
+
|
|
341
|
+
/* Bubbles — user only; assistant is plain prose (AI-chat convention) */
|
|
342
|
+
--aparte-message-content-bg-user: #2f2740;
|
|
343
|
+
--aparte-message-content-bg-assistant: transparent;
|
|
344
|
+
|
|
345
|
+
/* Text */
|
|
346
|
+
--aparte-text: #f2eee7;
|
|
347
|
+
--aparte-text-muted: #a89bb6;
|
|
348
|
+
--aparte-text-inverse: #17141c;
|
|
349
|
+
--aparte-name-color: #f2eee7;
|
|
350
|
+
--aparte-content-color: #ece8e2;
|
|
351
|
+
--aparte-timestamp-color: #7a7088;
|
|
352
|
+
|
|
353
|
+
/* Borders */
|
|
354
|
+
--aparte-border: #342a40;
|
|
355
|
+
|
|
356
|
+
/* Primary */
|
|
357
|
+
--aparte-primary: #d9a24b;
|
|
358
|
+
--aparte-primary-hover: #e7c588;
|
|
359
|
+
|
|
360
|
+
/* Input */
|
|
361
|
+
--aparte-input-bg: #211b28;
|
|
362
|
+
--aparte-input-border: #342a40;
|
|
363
|
+
--aparte-input-text: #f2eee7;
|
|
364
|
+
--aparte-input-placeholder: #7a7088;
|
|
365
|
+
|
|
366
|
+
/* Status */
|
|
367
|
+
--aparte-status-color: #94a3b8;
|
|
368
|
+
|
|
369
|
+
/* Thinking */
|
|
370
|
+
--aparte-thinking-border: #334155;
|
|
371
|
+
--aparte-thinking-bg: #1e293b;
|
|
372
|
+
--aparte-thinking-text: #94a3b8;
|
|
373
|
+
--aparte-thinking-content: #e5e7eb;
|
|
374
|
+
--aparte-thinking-content-bg: #0f172a;
|
|
375
|
+
|
|
376
|
+
/* Code */
|
|
377
|
+
--aparte-code-bg: #1e293b;
|
|
378
|
+
--aparte-code-header-bg: #334155;
|
|
379
|
+
--aparte-code-border: #475569;
|
|
380
|
+
--aparte-code-header-text: #94a3b8;
|
|
381
|
+
|
|
382
|
+
/* Progress */
|
|
383
|
+
--aparte-progress-bar-bg: #334155;
|
|
384
|
+
--aparte-scroll-btn-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
|
385
|
+
--aparte-progress-label: #e5e7eb;
|
|
386
|
+
|
|
387
|
+
/* File Tree */
|
|
388
|
+
--aparte-file-tree-bg: #1e293b;
|
|
389
|
+
--aparte-file-tree-border: #334155;
|
|
390
|
+
--aparte-file-tree-header-bg: #0f172a;
|
|
391
|
+
--aparte-file-tree-hover: #334155;
|
|
392
|
+
--aparte-file-tree-title: #94a3b8;
|
|
393
|
+
|
|
394
|
+
/* Error segment */
|
|
395
|
+
--aparte-error-bg: #2d1b1b;
|
|
396
|
+
--aparte-error-border: #7f1d1d;
|
|
397
|
+
--aparte-error-solid: #f87171;
|
|
398
|
+
--aparte-error-text: #fca5a5;
|
|
399
|
+
--aparte-error-title: #fecaca;
|
|
400
|
+
|
|
401
|
+
/* Prose */
|
|
402
|
+
--aparte-prose-blockquote-border: #475569;
|
|
403
|
+
--aparte-prose-code-bg: #334155;
|
|
404
|
+
|
|
405
|
+
/* Conversation List (dark overrides) */
|
|
406
|
+
--aparte-conv-item-bg-hover: #334155;
|
|
407
|
+
--aparte-conv-item-bg-active: #334155;
|
|
408
|
+
--aparte-conv-delete-color: #64748b;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* =========================================
|
|
412
|
+
aparte-chat (the drop-in shell)
|
|
413
|
+
Composes a viewport + composer as a flex column. Size the element yourself
|
|
414
|
+
(a height, or let it fill a sized parent); the viewport grows and scrolls and
|
|
415
|
+
the composer sits below it. Mirrors the framework auto-center layout for the
|
|
416
|
+
vanilla viewport, which otherwise has no flex sizing of its own.
|
|
417
|
+
========================================= */
|
|
418
|
+
|
|
419
|
+
/* Both host shapes core recognises get the same layout: the vanilla
|
|
420
|
+
<aparte-chat> element AND a framework wrapper's `[data-aparte-chat]` root
|
|
421
|
+
(React/Vue/Svelte/Angular render `<div data-aparte-chat>`). `[data-aparte-chat]`
|
|
422
|
+
is the SAME selector core uses to resolve the host (see aparte-client /
|
|
423
|
+
aparte-chat-bubble), so one rule covers both — no wrapper-specific class. */
|
|
424
|
+
aparte-chat,
|
|
425
|
+
[data-aparte-chat] {
|
|
426
|
+
display: flex;
|
|
427
|
+
flex-direction: column;
|
|
428
|
+
/* Fill the parent by default so the height:100% chain the inner scroll container
|
|
429
|
+
relies on has a definite anchor. Size the element yourself — a height on it, or
|
|
430
|
+
a sized parent. */
|
|
431
|
+
height: 100%;
|
|
432
|
+
width: 100%;
|
|
433
|
+
overflow: hidden;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* The viewport takes the space left by the composer; the standalone height:100%
|
|
437
|
+
default resolves against the shell's definite height above, and the inner
|
|
438
|
+
.aparte-viewport-container keeps doing the scrolling (styled scrollbar, wheel,
|
|
439
|
+
auto-scroll, scroll button all stay wired to it). */
|
|
440
|
+
aparte-chat > aparte-chat-viewport,
|
|
441
|
+
[data-aparte-chat] > aparte-chat-viewport {
|
|
442
|
+
flex: 1 1 auto;
|
|
443
|
+
min-height: 0;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* Model-selection gate (opt-in via AparteConfig.setRequireModelSelection): grey the
|
|
447
|
+
composer and block its send button until a model is selected — e.g. while the
|
|
448
|
+
model selector is still fetching. Ungates automatically on selection.
|
|
449
|
+
Unscoped so it greys the composer in EVERY host (vanilla shell + all wrappers),
|
|
450
|
+
not only a `[data-aparte-chat]` direct child. */
|
|
451
|
+
aparte-composer[data-model-gated] {
|
|
452
|
+
opacity: 0.55;
|
|
453
|
+
}
|
|
454
|
+
aparte-composer[data-model-gated] aparte-composer-send {
|
|
455
|
+
pointer-events: none;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
aparte-composer {
|
|
459
|
+
flex: 0 0 auto;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* center-empty: the shell centers the composer as a welcome state until the first
|
|
463
|
+
message, then slides to the normal layout. The component toggles [data-empty]
|
|
464
|
+
on itself by watching its viewport — only `flex-grow` animates, so the composer
|
|
465
|
+
glides to the bottom instead of snapping. */
|
|
466
|
+
aparte-chat[center-empty] > aparte-chat-viewport {
|
|
467
|
+
transition: flex-grow 0.3s ease;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
aparte-chat[center-empty][data-empty] {
|
|
471
|
+
justify-content: center;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
aparte-chat[center-empty][data-empty] > aparte-chat-viewport {
|
|
475
|
+
flex-grow: 0;
|
|
476
|
+
/* Release the standalone `height: 100%` (set on the viewport element for the
|
|
477
|
+
scroll chain): an explicit height ignores `flex-grow: 0`, so the empty viewport
|
|
478
|
+
would still fill the shell and leave `justify-content: center` no room to center
|
|
479
|
+
the composer. Empty = nothing to scroll, so auto height is safe here; the moment
|
|
480
|
+
a message lands, [data-empty] drops and height: 100% (scroll chain) is back. */
|
|
481
|
+
height: auto;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
@media (prefers-reduced-motion: reduce) {
|
|
485
|
+
aparte-chat[center-empty] > aparte-chat-viewport {
|
|
486
|
+
transition-duration: 0.01ms;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* =========================================
|
|
491
|
+
aparte-chat-viewport
|
|
492
|
+
========================================= */
|
|
493
|
+
|
|
494
|
+
aparte-chat-viewport {
|
|
495
|
+
display: block;
|
|
496
|
+
width: 100%;
|
|
497
|
+
height: 100%;
|
|
498
|
+
overflow: hidden;
|
|
499
|
+
contain: layout style;
|
|
500
|
+
/* Container-query root: children adapt to the WIDGET's width, not the
|
|
501
|
+
viewport's — an embedded chat can be narrow inside a wide page. */
|
|
502
|
+
container-type: inline-size;
|
|
503
|
+
text-align: left;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.aparte-viewport-container {
|
|
507
|
+
display: flex;
|
|
508
|
+
flex-direction: column;
|
|
509
|
+
height: 100%;
|
|
510
|
+
width: 100%;
|
|
511
|
+
overflow-y: auto;
|
|
512
|
+
overflow-x: hidden;
|
|
513
|
+
overscroll-behavior: contain;
|
|
514
|
+
scrollbar-width: thin;
|
|
515
|
+
scrollbar-color: var(--aparte-neutral, #6b7280) transparent;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.aparte-viewport-container::-webkit-scrollbar {
|
|
519
|
+
width: var(--aparte-scrollbar-width, 6px);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.aparte-viewport-container::-webkit-scrollbar-track {
|
|
523
|
+
background: transparent;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.aparte-viewport-container::-webkit-scrollbar-thumb {
|
|
527
|
+
background: var(--aparte-neutral, #6b7280);
|
|
528
|
+
border-radius: var(--aparte-radius-xs);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.aparte-viewport-container::-webkit-scrollbar-thumb:hover {
|
|
532
|
+
background: var(--aparte-secondary, #9ca3af);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.aparte-messages-wrapper {
|
|
536
|
+
display: flex;
|
|
537
|
+
flex-direction: column;
|
|
538
|
+
gap: var(--aparte-message-gap, 0);
|
|
539
|
+
padding: var(--aparte-viewport-padding, 16px);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* ─── Scroll-to-bottom button ─────────────────────────────────────────────── */
|
|
543
|
+
|
|
544
|
+
.aparte-scroll-btn {
|
|
545
|
+
position: absolute;
|
|
546
|
+
bottom: var(--aparte-space-8, 16px);
|
|
547
|
+
left: 50%;
|
|
548
|
+
transform: translateX(-50%);
|
|
549
|
+
z-index: 10;
|
|
550
|
+
width: var(--aparte-scroll-btn-size, 36px);
|
|
551
|
+
height: var(--aparte-scroll-btn-size, 36px);
|
|
552
|
+
border-radius: 50%;
|
|
553
|
+
background: var(--aparte-scroll-btn-bg);
|
|
554
|
+
color: var(--aparte-scroll-btn-color);
|
|
555
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-scroll-btn-border);
|
|
556
|
+
box-shadow: var(--aparte-scroll-btn-shadow);
|
|
557
|
+
cursor: pointer;
|
|
558
|
+
display: flex;
|
|
559
|
+
align-items: center;
|
|
560
|
+
justify-content: center;
|
|
561
|
+
transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s ease;
|
|
562
|
+
pointer-events: auto;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.aparte-scroll-btn:hover {
|
|
566
|
+
background: var(--aparte-scroll-btn-hover-bg);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.aparte-scroll-btn--hidden {
|
|
570
|
+
opacity: 0;
|
|
571
|
+
pointer-events: none;
|
|
572
|
+
transform: translateX(-50%) translateY(8px);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* ─── Bottom spacer ───────────────────────────────────────────────────────── */
|
|
576
|
+
|
|
577
|
+
.aparte-bottom-spacer {
|
|
578
|
+
flex-shrink: 0;
|
|
579
|
+
height: 0px;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/* ─── Framework-managed viewport ──────────────────────────────────────────────
|
|
583
|
+
When a framework wrapper (React/Vue/Svelte/Angular) owns the bubble elements,
|
|
584
|
+
the viewport does NOT relocate them into an internal wrapper (that would break
|
|
585
|
+
the framework's DOM reconciliation). Instead the HOST itself is the scroll
|
|
586
|
+
surface — these rules mirror .aparte-viewport-container + .aparte-messages-wrapper
|
|
587
|
+
onto the host, and the bottom spacer becomes an additive padding (no element,
|
|
588
|
+
so it can't collide with the framework's children). */
|
|
589
|
+
aparte-chat-viewport.aparte-viewport--framework,
|
|
590
|
+
aparte-chat-viewport[framework-managed] {
|
|
591
|
+
overflow-y: auto;
|
|
592
|
+
overflow-x: hidden;
|
|
593
|
+
overscroll-behavior: contain;
|
|
594
|
+
display: flex;
|
|
595
|
+
flex-direction: column;
|
|
596
|
+
gap: var(--aparte-message-gap, 0);
|
|
597
|
+
padding: var(--aparte-viewport-padding, 16px);
|
|
598
|
+
padding-bottom: calc(var(--aparte-viewport-padding, 16px) + var(--aparte-fw-spacer, 0px));
|
|
599
|
+
scrollbar-width: thin;
|
|
600
|
+
scrollbar-color: var(--aparte-neutral, #6b7280) transparent;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/* The framework wrapper renders bubbles as DIRECT flex children of the viewport
|
|
604
|
+
(no inner wrapper, unlike the vanilla path). With the viewport as a fixed-height
|
|
605
|
+
flex column, those children would `flex-shrink` to fit — compressing content
|
|
606
|
+
instead of overflowing, so nothing scrolls. Pin their size so the content grows
|
|
607
|
+
past the viewport and the scroll surface actually scrolls. */
|
|
608
|
+
aparte-chat-viewport.aparte-viewport--framework > *,
|
|
609
|
+
aparte-chat-viewport[framework-managed] > * {
|
|
610
|
+
flex-shrink: 0;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar {
|
|
614
|
+
width: var(--aparte-scrollbar-width, 6px);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar-track {
|
|
618
|
+
background: transparent;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar-thumb {
|
|
622
|
+
background: var(--aparte-neutral, #6b7280);
|
|
623
|
+
border-radius: var(--aparte-radius-xs);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/* The scroll button lives INSIDE the scrolling host here (last child), so it
|
|
627
|
+
floats with `position: sticky` instead of the `absolute` used in core mode
|
|
628
|
+
(where it sits outside the scroll container). */
|
|
629
|
+
aparte-chat-viewport.aparte-viewport--framework > .aparte-scroll-btn {
|
|
630
|
+
position: sticky;
|
|
631
|
+
bottom: var(--aparte-space-8, 16px);
|
|
632
|
+
left: auto;
|
|
633
|
+
align-self: center;
|
|
634
|
+
transform: none;
|
|
635
|
+
flex-shrink: 0;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
aparte-chat-viewport.aparte-viewport--framework > .aparte-scroll-btn.aparte-scroll-btn--hidden {
|
|
639
|
+
transform: translateY(8px);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/* =========================================
|
|
643
|
+
aparte-chat-bubble
|
|
644
|
+
========================================= */
|
|
645
|
+
|
|
646
|
+
aparte-chat-bubble {
|
|
647
|
+
display: block;
|
|
648
|
+
width: 100%;
|
|
649
|
+
overflow: hidden;
|
|
650
|
+
/* Each bubble is its own layout/paint boundary, and bubbles scrolled out
|
|
651
|
+
of the viewport are skipped entirely (layout + paint) via
|
|
652
|
+
content-visibility. While a message streams the user is pinned to the
|
|
653
|
+
bottom, so every bubble above the live one stops costing a paint on each
|
|
654
|
+
token — that reclaimed GPU time goes back to the WebGPU decode.
|
|
655
|
+
contain-intrinsic-size keeps the scrollbar stable: the `auto` keyword
|
|
656
|
+
reuses a bubble's real height once it has been measured; the 320px is
|
|
657
|
+
only a fallback for bubbles that have never been rendered yet. */
|
|
658
|
+
contain: layout style paint;
|
|
659
|
+
content-visibility: auto;
|
|
660
|
+
contain-intrinsic-size: auto 320px;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.aparte-message {
|
|
664
|
+
display: flex;
|
|
665
|
+
gap: var(--aparte-message-gap, 12px);
|
|
666
|
+
padding: var(--aparte-message-padding, 16px 12px);
|
|
667
|
+
width: 100%;
|
|
668
|
+
max-width: var(--aparte-message-max-width, 800px);
|
|
669
|
+
margin: 0 auto;
|
|
670
|
+
min-width: 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.aparte-avatar {
|
|
674
|
+
flex-shrink: 0;
|
|
675
|
+
width: var(--aparte-avatar-size, 32px);
|
|
676
|
+
height: var(--aparte-avatar-size, 32px);
|
|
677
|
+
border-radius: var(--aparte-avatar-radius, 6px);
|
|
678
|
+
display: flex;
|
|
679
|
+
align-items: center;
|
|
680
|
+
justify-content: center;
|
|
681
|
+
font-size: var(--aparte-avatar-font-size, 14px);
|
|
682
|
+
font-weight: var(--aparte-font-weight-semibold, 600);
|
|
683
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/* No message avatar by default — the slot only shows once an AvatarProvider
|
|
687
|
+
(or a consumer) fills it. Role is carried by layout + colour instead. */
|
|
688
|
+
.aparte-avatar:empty {
|
|
689
|
+
display: none;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.aparte-avatar[data-role="user"] {
|
|
693
|
+
background: var(--aparte-avatar-bg-user, #6366f1);
|
|
694
|
+
color: var(--aparte-avatar-text-user, #ffffff);
|
|
695
|
+
background-image: var(--aparte-avatar-image-user, none);
|
|
696
|
+
background-size: var(--aparte-avatar-image-size, 90%);
|
|
697
|
+
background-repeat: no-repeat;
|
|
698
|
+
background-position: center;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.aparte-avatar[data-role="assistant"] {
|
|
702
|
+
background: var(--aparte-avatar-bg-assistant, #10b981);
|
|
703
|
+
color: var(--aparte-avatar-text-assistant, #ffffff);
|
|
704
|
+
background-image: var(--aparte-avatar-image-assistant, none);
|
|
705
|
+
background-size: var(--aparte-avatar-image-size, 90%);
|
|
706
|
+
background-repeat: no-repeat;
|
|
707
|
+
background-position: center;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.aparte-body {
|
|
711
|
+
flex: 1;
|
|
712
|
+
min-width: 0;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/* The message bubble — the surface fills ONLY the content (attachments +
|
|
716
|
+
segments + text). The sender name (above) and the action bar (below) are
|
|
717
|
+
siblings in .aparte-body, so they stay OUTSIDE the coloured surface. */
|
|
718
|
+
.aparte-message-content {
|
|
719
|
+
border-radius: var(--aparte-message-content-radius, 0);
|
|
720
|
+
max-width: 100%;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/* AI-chat convention (not messaging): the USER message is a subtle bubble that
|
|
724
|
+
hugs its text; the ASSISTANT message is plain full-width prose — no bubble,
|
|
725
|
+
like ChatGPT / Claude. */
|
|
726
|
+
.aparte-message[data-role="user"] .aparte-message-content {
|
|
727
|
+
width: fit-content;
|
|
728
|
+
padding: var(--aparte-message-content-padding, 0);
|
|
729
|
+
background: var(--aparte-message-content-bg-user, transparent);
|
|
730
|
+
color: var(--aparte-message-content-text-user, var(--aparte-text));
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.aparte-message[data-role="assistant"] .aparte-message-content {
|
|
734
|
+
background: var(--aparte-message-content-bg-assistant, transparent);
|
|
735
|
+
color: var(--aparte-message-content-text-assistant, var(--aparte-text));
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.aparte-header {
|
|
739
|
+
display: flex;
|
|
740
|
+
align-items: center;
|
|
741
|
+
gap: var(--aparte-space-4, 8px);
|
|
742
|
+
margin-bottom: var(--aparte-space-3, 6px);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.aparte-name {
|
|
746
|
+
font-size: var(--aparte-name-font-size, 14px);
|
|
747
|
+
font-weight: var(--aparte-font-weight-semibold, 600);
|
|
748
|
+
color: var(--aparte-name-color, #1f2937);
|
|
749
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.aparte-timestamp {
|
|
753
|
+
font-size: var(--aparte-timestamp-font-size, 12px);
|
|
754
|
+
color: var(--aparte-timestamp-color, #9ca3af);
|
|
755
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.aparte-content {
|
|
759
|
+
font-size: var(--aparte-content-font-size, 15px);
|
|
760
|
+
line-height: var(--aparte-content-line-height, 1.7);
|
|
761
|
+
color: var(--aparte-content-color, #374151);
|
|
762
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
763
|
+
white-space: normal;
|
|
764
|
+
word-wrap: break-word;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.aparte-segments {
|
|
768
|
+
font-size: var(--aparte-content-font-size, 15px);
|
|
769
|
+
line-height: var(--aparte-content-line-height, 1.7);
|
|
770
|
+
color: var(--aparte-content-color, #374151);
|
|
771
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.aparte-segments:empty {
|
|
775
|
+
display: none;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/* =========================================
|
|
779
|
+
Attachments
|
|
780
|
+
========================================= */
|
|
781
|
+
|
|
782
|
+
.aparte-attachments {
|
|
783
|
+
display: flex;
|
|
784
|
+
flex-wrap: wrap;
|
|
785
|
+
/* Bubble attachments only ever render for user messages — anchor right. */
|
|
786
|
+
justify-content: flex-end;
|
|
787
|
+
gap: var(--aparte-space-3, 6px);
|
|
788
|
+
margin-bottom: var(--aparte-space-4, 8px);
|
|
789
|
+
/* Really small tiles inside the conversation. */
|
|
790
|
+
--aparte-attachment-image-size: 40px;
|
|
791
|
+
/* Many attachments → cap the height and scroll instead of growing forever. */
|
|
792
|
+
max-height: var(--aparte-attachments-max-height, 140px);
|
|
793
|
+
overflow-y: auto;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* The class `display: flex` above would otherwise override the `hidden`
|
|
797
|
+
attribute — restore it so an empty attachment strip takes no space. */
|
|
798
|
+
.aparte-attachments[hidden] {
|
|
799
|
+
display: none;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/* ── Attachment thumbnail tile ──────────────────────────────────────────────
|
|
803
|
+
Shared by the composer attachment preview and the sent-message attachment
|
|
804
|
+
strip. A square that shows the image itself (or a file glyph); the filename
|
|
805
|
+
and — in the composer — a remove button surface on hover. */
|
|
806
|
+
.aparte-thumb {
|
|
807
|
+
position: relative;
|
|
808
|
+
width: var(--aparte-attachment-image-size, 56px);
|
|
809
|
+
height: var(--aparte-attachment-image-size, 56px);
|
|
810
|
+
flex-shrink: 0;
|
|
811
|
+
border-radius: var(--aparte-thumb-radius, 8px);
|
|
812
|
+
overflow: hidden;
|
|
813
|
+
box-sizing: border-box;
|
|
814
|
+
background: var(--aparte-attachment-chip-bg, var(--aparte-surface-2));
|
|
815
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-attachment-chip-border, var(--aparte-border));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.aparte-thumb--image {
|
|
819
|
+
cursor: pointer;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.aparte-thumb__img {
|
|
823
|
+
width: 100%;
|
|
824
|
+
height: 100%;
|
|
825
|
+
object-fit: cover;
|
|
826
|
+
display: block;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.aparte-thumb--file {
|
|
830
|
+
display: flex;
|
|
831
|
+
align-items: center;
|
|
832
|
+
justify-content: center;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.aparte-thumb__ext {
|
|
836
|
+
font-size: var(--aparte-font-size-xs, 11px);
|
|
837
|
+
font-weight: var(--aparte-font-weight-bold, 700);
|
|
838
|
+
letter-spacing: 0.03em;
|
|
839
|
+
color: var(--aparte-text-muted, var(--aparte-text));
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.aparte-thumb__name {
|
|
843
|
+
position: absolute;
|
|
844
|
+
left: 0;
|
|
845
|
+
right: 0;
|
|
846
|
+
bottom: 0;
|
|
847
|
+
padding: var(--aparte-thumb-name-padding, 14px 5px 4px);
|
|
848
|
+
font-size: var(--aparte-font-size-2xs, 10px);
|
|
849
|
+
line-height: var(--aparte-line-height-tight, 1.25);
|
|
850
|
+
color: var(--aparte-thumb-name-color, #fff);
|
|
851
|
+
background: var(--aparte-thumb-name-scrim, linear-gradient(to top, rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0)));
|
|
852
|
+
white-space: nowrap;
|
|
853
|
+
overflow: hidden;
|
|
854
|
+
text-overflow: ellipsis;
|
|
855
|
+
opacity: 0;
|
|
856
|
+
transition: opacity 0.15s ease;
|
|
857
|
+
pointer-events: none;
|
|
858
|
+
}
|
|
859
|
+
.aparte-thumb:hover .aparte-thumb__name {
|
|
860
|
+
opacity: 1;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.aparte-thumb__remove {
|
|
864
|
+
position: absolute;
|
|
865
|
+
top: var(--aparte-thumb-remove-inset, 3px);
|
|
866
|
+
right: var(--aparte-thumb-remove-inset, 3px);
|
|
867
|
+
width: var(--aparte-thumb-remove-size, 18px);
|
|
868
|
+
height: var(--aparte-thumb-remove-size, 18px);
|
|
869
|
+
display: flex;
|
|
870
|
+
align-items: center;
|
|
871
|
+
justify-content: center;
|
|
872
|
+
padding: 0;
|
|
873
|
+
border: none;
|
|
874
|
+
border-radius: 50%;
|
|
875
|
+
background: var(--aparte-thumb-remove-bg, rgba(0, 0, 0, 0.6));
|
|
876
|
+
color: var(--aparte-thumb-remove-color, #fff);
|
|
877
|
+
cursor: pointer;
|
|
878
|
+
opacity: 0;
|
|
879
|
+
transition: opacity 0.15s ease, background 0.15s ease;
|
|
880
|
+
}
|
|
881
|
+
.aparte-thumb:hover .aparte-thumb__remove {
|
|
882
|
+
opacity: 1;
|
|
883
|
+
}
|
|
884
|
+
.aparte-thumb__remove:hover {
|
|
885
|
+
background: var(--aparte-thumb-remove-bg-hover, rgba(0, 0, 0, 0.85));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
/* =========================================
|
|
889
|
+
Action Bar
|
|
890
|
+
========================================= */
|
|
891
|
+
|
|
892
|
+
.aparte-footer {
|
|
893
|
+
display: flex;
|
|
894
|
+
align-items: center;
|
|
895
|
+
gap: var(--aparte-action-bar-gap, 4px);
|
|
896
|
+
margin-top: var(--aparte-space-3, 6px);
|
|
897
|
+
min-height: var(--aparte-action-bar-btn-size, 28px);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.aparte-action-bar {
|
|
901
|
+
display: flex;
|
|
902
|
+
align-items: center;
|
|
903
|
+
gap: var(--aparte-action-bar-gap, 4px);
|
|
904
|
+
opacity: 0;
|
|
905
|
+
transition: opacity 0.15s ease;
|
|
906
|
+
height: var(--aparte-action-bar-btn-size, 28px);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
.aparte-message:hover .aparte-action-bar,
|
|
910
|
+
.aparte-message:focus-within .aparte-action-bar {
|
|
911
|
+
opacity: 1;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* Last assistant message: action bar always visible — but NOT while streaming */
|
|
915
|
+
aparte-chat-bubble:last-of-type .aparte-message[data-role="assistant"]:not(.aparte-message-streaming) .aparte-action-bar {
|
|
916
|
+
opacity: 1;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/* Hide footer (action bar + branch picker) entirely while streaming */
|
|
920
|
+
.aparte-message-streaming .aparte-footer {
|
|
921
|
+
display: none;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.aparte-action-btn {
|
|
925
|
+
display: inline-flex;
|
|
926
|
+
align-items: center;
|
|
927
|
+
justify-content: center;
|
|
928
|
+
width: var(--aparte-action-bar-btn-size, 28px);
|
|
929
|
+
height: var(--aparte-action-bar-btn-size, 28px);
|
|
930
|
+
border: none;
|
|
931
|
+
border-radius: var(--aparte-radius-sm, 4px);
|
|
932
|
+
background: transparent;
|
|
933
|
+
color: var(--aparte-action-bar-btn-color, var(--aparte-text-muted));
|
|
934
|
+
cursor: pointer;
|
|
935
|
+
padding: 0;
|
|
936
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
937
|
+
flex-shrink: 0;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.aparte-action-btn:hover {
|
|
941
|
+
background: var(--aparte-action-bar-btn-hover-bg, var(--aparte-surface-2));
|
|
942
|
+
color: var(--aparte-action-bar-btn-hover-color, var(--aparte-text));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.aparte-action-btn[data-copied] {
|
|
946
|
+
color: var(--aparte-success, #10b981);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.aparte-action-btn[data-submitted] {
|
|
950
|
+
color: var(--aparte-primary, #6366f1);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/* =========================================
|
|
954
|
+
Branch Picker
|
|
955
|
+
========================================= */
|
|
956
|
+
|
|
957
|
+
.aparte-branch-picker {
|
|
958
|
+
display: flex;
|
|
959
|
+
align-items: center;
|
|
960
|
+
gap: var(--aparte-branch-picker-gap, 4px);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/* [hidden] is overridden by display:flex — force it back */
|
|
964
|
+
.aparte-branch-picker[hidden] {
|
|
965
|
+
display: none;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.aparte-branch-prev,
|
|
969
|
+
.aparte-branch-next {
|
|
970
|
+
display: inline-flex;
|
|
971
|
+
align-items: center;
|
|
972
|
+
justify-content: center;
|
|
973
|
+
width: var(--aparte-branch-picker-btn-size, 20px);
|
|
974
|
+
height: var(--aparte-branch-picker-btn-size, 20px);
|
|
975
|
+
border: none;
|
|
976
|
+
border-radius: var(--aparte-radius-sm, 4px);
|
|
977
|
+
background: transparent;
|
|
978
|
+
color: var(--aparte-branch-picker-btn-color, var(--aparte-text-muted));
|
|
979
|
+
cursor: pointer;
|
|
980
|
+
padding: 0;
|
|
981
|
+
font-size: var(--aparte-branch-picker-btn-icon-size, 16px);
|
|
982
|
+
line-height: var(--aparte-line-height-none, 1);
|
|
983
|
+
transition: color 0.15s ease, background 0.15s ease;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.aparte-branch-prev:hover:not(:disabled),
|
|
987
|
+
.aparte-branch-next:hover:not(:disabled) {
|
|
988
|
+
color: var(--aparte-branch-picker-btn-hover-color, var(--aparte-text));
|
|
989
|
+
background: var(--aparte-action-bar-btn-hover-bg, var(--aparte-surface-2));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.aparte-branch-prev:disabled,
|
|
993
|
+
.aparte-branch-next:disabled {
|
|
994
|
+
opacity: 0.3;
|
|
995
|
+
cursor: default;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
.aparte-branch-label {
|
|
999
|
+
font-size: var(--aparte-branch-picker-label-size, 12px);
|
|
1000
|
+
color: var(--aparte-branch-picker-label-color, var(--aparte-text-muted));
|
|
1001
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
1002
|
+
min-width: var(--aparte-branch-picker-label-min-width, 32px);
|
|
1003
|
+
text-align: center;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/* =========================================
|
|
1007
|
+
Edit mode
|
|
1008
|
+
========================================= */
|
|
1009
|
+
|
|
1010
|
+
/* Inline editor: the composer's contenteditable primitive, given the composer
|
|
1011
|
+
shell's box (bordered surface) so it reads as the same field. The inner
|
|
1012
|
+
.aparte-ci-editor inherits its padding/font/caret from the shared composer rule. */
|
|
1013
|
+
.aparte-message[data-editing] aparte-composer-input {
|
|
1014
|
+
display: block;
|
|
1015
|
+
margin: var(--aparte-space-2, 4px) 0;
|
|
1016
|
+
background: var(--aparte-input-bg, var(--aparte-surface-1));
|
|
1017
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-input-border, var(--aparte-border));
|
|
1018
|
+
border-radius: var(--aparte-radius-input, 12px);
|
|
1019
|
+
box-sizing: border-box;
|
|
1020
|
+
transition: border-color 0.2s;
|
|
1021
|
+
}
|
|
1022
|
+
.aparte-message[data-editing] aparte-composer-input:focus-within {
|
|
1023
|
+
border-color: var(--aparte-input-focus-border, var(--aparte-primary));
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/* Edit mode keeps the action bar (now ✓ / ✗) visible even when the editor
|
|
1027
|
+
is not focused — otherwise the user can't reach the save button. */
|
|
1028
|
+
.aparte-message[data-editing] .aparte-action-bar {
|
|
1029
|
+
opacity: 1;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.aparte-action-btn.aparte-action-edit-save {
|
|
1033
|
+
color: var(--aparte-success, #16a34a);
|
|
1034
|
+
}
|
|
1035
|
+
.aparte-action-btn.aparte-action-edit-save:hover {
|
|
1036
|
+
background: var(--aparte-success-surface, rgba(34, 197, 94, 0.14));
|
|
1037
|
+
color: var(--aparte-success, #16a34a);
|
|
1038
|
+
}
|
|
1039
|
+
.aparte-action-btn.aparte-action-edit-cancel {
|
|
1040
|
+
color: var(--aparte-error, #dc2626);
|
|
1041
|
+
}
|
|
1042
|
+
.aparte-action-btn.aparte-action-edit-cancel:hover {
|
|
1043
|
+
background: var(--aparte-error-surface, rgba(239, 68, 68, 0.14));
|
|
1044
|
+
color: var(--aparte-error, #dc2626);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
/* =========================================
|
|
1049
|
+
Legacy composer input utility classes
|
|
1050
|
+
========================================= */
|
|
1051
|
+
|
|
1052
|
+
.aparte-input-wrapper {
|
|
1053
|
+
display: flex;
|
|
1054
|
+
align-items: flex-end;
|
|
1055
|
+
gap: var(--aparte-input-gap, 8px);
|
|
1056
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1057
|
+
background: transparent;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/* Action slots */
|
|
1061
|
+
.aparte-actions-left,
|
|
1062
|
+
.aparte-actions-right {
|
|
1063
|
+
display: flex;
|
|
1064
|
+
align-items: center;
|
|
1065
|
+
gap: var(--aparte-space-2, 4px);
|
|
1066
|
+
flex-shrink: 0;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
.aparte-input-container {
|
|
1070
|
+
flex: 1;
|
|
1071
|
+
min-height: var(--aparte-input-container-min-height, 44px);
|
|
1072
|
+
/* Matches _minHeight default */
|
|
1073
|
+
display: flex;
|
|
1074
|
+
flex-direction: column;
|
|
1075
|
+
/* justify-content: center; Removed to fix cursor pos */
|
|
1076
|
+
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.aparte-editor {
|
|
1080
|
+
width: 100%;
|
|
1081
|
+
max-height: var(--aparte-input-editor-max-height, 200px);
|
|
1082
|
+
/* Matches _maxHeight default */
|
|
1083
|
+
overflow-y: auto;
|
|
1084
|
+
outline: none;
|
|
1085
|
+
border: none;
|
|
1086
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
1087
|
+
font-size: var(--aparte-input-editor-font-size, 15px);
|
|
1088
|
+
line-height: var(--aparte-line-height-normal, 1.5);
|
|
1089
|
+
color: var(--aparte-input-text, #374151);
|
|
1090
|
+
background: transparent;
|
|
1091
|
+
padding: var(--aparte-space-5, 10px) 0;
|
|
1092
|
+
resize: none;
|
|
1093
|
+
text-align: left;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/* Placeholder */
|
|
1097
|
+
.aparte-editor:empty:before {
|
|
1098
|
+
content: attr(data-placeholder);
|
|
1099
|
+
color: var(--aparte-input-placeholder, #9ca3af);
|
|
1100
|
+
pointer-events: none;
|
|
1101
|
+
display: block;
|
|
1102
|
+
/* Ensures proper rendering */
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/* Disabled state */
|
|
1106
|
+
.aparte-editor[contenteditable="false"] {
|
|
1107
|
+
opacity: 0.6;
|
|
1108
|
+
cursor: not-allowed;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.aparte-send-button {
|
|
1112
|
+
flex-shrink: 0;
|
|
1113
|
+
width: var(--aparte-send-btn-size, 36px);
|
|
1114
|
+
height: var(--aparte-send-btn-size, 36px);
|
|
1115
|
+
border-radius: var(--aparte-radius-send-btn);
|
|
1116
|
+
border: none;
|
|
1117
|
+
background: var(--aparte-primary, #6366f1);
|
|
1118
|
+
color: var(--aparte-on-primary, white);
|
|
1119
|
+
display: flex;
|
|
1120
|
+
align-items: center;
|
|
1121
|
+
justify-content: center;
|
|
1122
|
+
cursor: pointer;
|
|
1123
|
+
transition: background 0.2s, opacity 0.2s;
|
|
1124
|
+
padding: 0;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
.aparte-send-button:hover:not(:disabled) {
|
|
1128
|
+
background: var(--aparte-primary-hover, #4f46e5);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.aparte-send-button:disabled {
|
|
1132
|
+
opacity: 0.45;
|
|
1133
|
+
cursor: not-allowed;
|
|
1134
|
+
background: var(--aparte-send-disabled-bg, var(--aparte-primary));
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/* Action Buttons in Input */
|
|
1138
|
+
.aparte-action-button {
|
|
1139
|
+
background: transparent;
|
|
1140
|
+
border: none;
|
|
1141
|
+
color: var(--aparte-neutral, #6b7280);
|
|
1142
|
+
padding: var(--aparte-space-4, 8px);
|
|
1143
|
+
border-radius: var(--aparte-radius-action-btn);
|
|
1144
|
+
cursor: pointer;
|
|
1145
|
+
display: flex;
|
|
1146
|
+
align-items: center;
|
|
1147
|
+
justify-content: center;
|
|
1148
|
+
transition: color 0.15s, background-color 0.15s;
|
|
1149
|
+
width: var(--aparte-input-action-btn-size, 36px);
|
|
1150
|
+
height: var(--aparte-input-action-btn-size, 36px);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
.aparte-action-button:hover {
|
|
1154
|
+
color: var(--aparte-primary, #6366f1);
|
|
1155
|
+
/* Derive the hover tint from --aparte-primary instead of hardcoding indigo, so a
|
|
1156
|
+
custom theme's action buttons tint with its own accent. */
|
|
1157
|
+
background-color: color-mix(in srgb, var(--aparte-primary, #6366f1) 10%, transparent);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
.aparte-action-button svg {
|
|
1161
|
+
width: var(--aparte-input-action-btn-icon-size, 20px);
|
|
1162
|
+
height: var(--aparte-input-action-btn-icon-size, 20px);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/* =========================================
|
|
1166
|
+
Input Upper (for file chips, previews, etc.)
|
|
1167
|
+
========================================= */
|
|
1168
|
+
|
|
1169
|
+
.aparte-input-upper {
|
|
1170
|
+
display: none; /* shown by JS when chips are added */
|
|
1171
|
+
flex-wrap: wrap;
|
|
1172
|
+
align-items: center;
|
|
1173
|
+
gap: var(--aparte-space-4, 8px);
|
|
1174
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1175
|
+
border-bottom: var(--aparte-border-width, 1px) solid var(--aparte-border, #e5e7eb);
|
|
1176
|
+
font-size: var(--aparte-font-size-md, 13px);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.aparte-input-upper.has-content {
|
|
1180
|
+
display: flex;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
/* =========================================
|
|
1184
|
+
Input Footer (for Model Selector, etc.)
|
|
1185
|
+
========================================= */
|
|
1186
|
+
|
|
1187
|
+
.aparte-input-footer {
|
|
1188
|
+
display: flex;
|
|
1189
|
+
align-items: center;
|
|
1190
|
+
gap: var(--aparte-space-6, 12px);
|
|
1191
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1192
|
+
border-top: var(--aparte-border-width, 1px) solid var(--aparte-border, #e5e7eb);
|
|
1193
|
+
font-size: var(--aparte-font-size-md, 13px);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
.aparte-input-footer:empty {
|
|
1197
|
+
display: none;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/* Slot areas */
|
|
1201
|
+
.aparte-input-footer slot[name="footer-left"] {
|
|
1202
|
+
display: contents;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.aparte-input-footer slot[name="footer-center"] {
|
|
1206
|
+
flex: 1;
|
|
1207
|
+
display: contents;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.aparte-input-footer slot[name="footer-right"] {
|
|
1211
|
+
display: contents;
|
|
1212
|
+
margin-inline-start: auto;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/* Model Selector Component */
|
|
1216
|
+
aparte-model-selector {
|
|
1217
|
+
display: flex;
|
|
1218
|
+
align-items: center;
|
|
1219
|
+
gap: var(--aparte-space-4, 8px);
|
|
1220
|
+
}
|
|
1221
|
+
/* Respect native hidden attribute — overrides the display:flex above */
|
|
1222
|
+
aparte-model-selector[hidden] { display: none !important; }
|
|
1223
|
+
|
|
1224
|
+
.aparte-model-selector {
|
|
1225
|
+
display: flex;
|
|
1226
|
+
align-items: center;
|
|
1227
|
+
gap: var(--aparte-space-4, 8px);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.aparte-provider-select,
|
|
1231
|
+
.aparte-model-select {
|
|
1232
|
+
appearance: none;
|
|
1233
|
+
background: var(--aparte-surface-1, #ffffff);
|
|
1234
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-border, #e5e7eb);
|
|
1235
|
+
border-radius: var(--aparte-radius-select);
|
|
1236
|
+
padding: var(--aparte-space-3, 6px) 28px var(--aparte-space-3, 6px) var(--aparte-space-5, 10px);
|
|
1237
|
+
font-size: var(--aparte-font-size-md, 13px);
|
|
1238
|
+
font-family: var(--aparte-font-family, system-ui);
|
|
1239
|
+
color: var(--aparte-text, #1f2937);
|
|
1240
|
+
cursor: pointer;
|
|
1241
|
+
min-width: var(--aparte-select-min-width, 120px);
|
|
1242
|
+
/* Chevron: baked into a data-URI SVG (CSS vars can't interpolate into url()).
|
|
1243
|
+
The stroke colour is theme-matched via the [data-aparte-theme] override
|
|
1244
|
+
below rather than a single var — the one spot that needs two variants. */
|
|
1245
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
|
|
1246
|
+
background-repeat: no-repeat;
|
|
1247
|
+
background-position: right var(--aparte-space-4, 8px) center;
|
|
1248
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.aparte-provider-select:hover,
|
|
1252
|
+
.aparte-model-select:hover {
|
|
1253
|
+
border-color: var(--aparte-primary, #6366f1);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
.aparte-provider-select:focus,
|
|
1257
|
+
.aparte-model-select:focus {
|
|
1258
|
+
outline: none;
|
|
1259
|
+
border-color: var(--aparte-primary, #6366f1);
|
|
1260
|
+
box-shadow: var(--aparte-focus-ring, 0 0 0 3px rgba(99, 102, 241, 0.15));
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/* Dark mode overrides for selects */
|
|
1264
|
+
[data-aparte-theme="dark"] .aparte-provider-select,
|
|
1265
|
+
[data-aparte-theme="dark"] .aparte-model-select {
|
|
1266
|
+
background-color: var(--aparte-surface-1, #1e293b);
|
|
1267
|
+
border-color: var(--aparte-border, #334155);
|
|
1268
|
+
color: var(--aparte-text, #f1f5f9);
|
|
1269
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
/* =========================================
|
|
1274
|
+
aparte-chat-status
|
|
1275
|
+
========================================= */
|
|
1276
|
+
|
|
1277
|
+
aparte-chat-status {
|
|
1278
|
+
display: block;
|
|
1279
|
+
width: 100%;
|
|
1280
|
+
contain: layout style paint;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/* No layout footprint until the typing indicator is actually shown — otherwise the
|
|
1284
|
+
always-present element reserves height (visible via flex-shrink:0 in the
|
|
1285
|
+
framework-managed viewport) even on the empty/welcome screen. */
|
|
1286
|
+
aparte-chat-status:not([visible]) {
|
|
1287
|
+
display: none;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.aparte-status-container {
|
|
1291
|
+
display: flex;
|
|
1292
|
+
align-items: center;
|
|
1293
|
+
opacity: 0;
|
|
1294
|
+
transform: translateY(8px);
|
|
1295
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
1296
|
+
pointer-events: none;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.aparte-status-content {
|
|
1300
|
+
display: flex;
|
|
1301
|
+
align-items: center;
|
|
1302
|
+
gap: var(--aparte-space-4, 8px);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
.aparte-status-container[data-visible="true"] {
|
|
1306
|
+
opacity: 1;
|
|
1307
|
+
transform: translateY(0);
|
|
1308
|
+
pointer-events: auto;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
.aparte-status-text {
|
|
1312
|
+
font-size: var(--aparte-status-font-size, 13px);
|
|
1313
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
1314
|
+
color: var(--aparte-status-color, #6b7280);
|
|
1315
|
+
font-style: italic;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.aparte-dots {
|
|
1319
|
+
display: flex;
|
|
1320
|
+
align-items: center;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
.aparte-dot {
|
|
1324
|
+
width: var(--aparte-status-dot-size, 6px);
|
|
1325
|
+
height: var(--aparte-status-dot-size, 6px);
|
|
1326
|
+
background: var(--aparte-status-color, #6b7280);
|
|
1327
|
+
border-radius: 50%;
|
|
1328
|
+
animation: aparte-pulse 1.2s infinite ease-in-out;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/* Respect prefers-reduced-motion. Scoped to Aparte's own custom elements (never
|
|
1332
|
+
the consumer's page) — this covers every animated element the library renders
|
|
1333
|
+
inside them: typing dots, spinners, pipeline/artifact pulses, segment
|
|
1334
|
+
animations. Activity stays conveyed via aria-live / aria-busy. */
|
|
1335
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1336
|
+
aparte-chat-viewport *,
|
|
1337
|
+
aparte-chat-bubble *,
|
|
1338
|
+
aparte-composer *,
|
|
1339
|
+
aparte-chat-status *,
|
|
1340
|
+
aparte-conversation-list *,
|
|
1341
|
+
aparte-select *,
|
|
1342
|
+
aparte-progress-spinner * {
|
|
1343
|
+
animation-duration: 0.01ms !important;
|
|
1344
|
+
animation-iteration-count: 1 !important;
|
|
1345
|
+
transition-duration: 0.01ms !important;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
@keyframes aparte-pulse {
|
|
1350
|
+
0%, 100% {
|
|
1351
|
+
opacity: 0.3;
|
|
1352
|
+
transform: scale(0.75);
|
|
1353
|
+
}
|
|
1354
|
+
50% {
|
|
1355
|
+
opacity: 1;
|
|
1356
|
+
transform: scale(1);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
/* =========================================
|
|
1361
|
+
Segment Renderers (Global Defaults)
|
|
1362
|
+
========================================= */
|
|
1363
|
+
|
|
1364
|
+
/* Text */
|
|
1365
|
+
.segment-text {
|
|
1366
|
+
word-wrap: break-word;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/* =========================================
|
|
1370
|
+
Prose — reset-agnostic typography
|
|
1371
|
+
Compact defaults for chat context.
|
|
1372
|
+
Customizable via --aparte-prose-* variables.
|
|
1373
|
+
========================================= */
|
|
1374
|
+
|
|
1375
|
+
.aparte-content,
|
|
1376
|
+
.segment-content {
|
|
1377
|
+
white-space: normal;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
.aparte-content p,
|
|
1381
|
+
.segment-content p {
|
|
1382
|
+
margin: var(--aparte-prose-p-margin, 0.4em 0);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
.aparte-content p:first-child,
|
|
1386
|
+
.segment-content p:first-child {
|
|
1387
|
+
margin-top: 0;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
.aparte-content p:last-child,
|
|
1391
|
+
.segment-content p:last-child {
|
|
1392
|
+
margin-bottom: 0;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
.aparte-content h1, .segment-content h1 { font-size: var(--aparte-prose-h1-size, 1.4em); font-weight: var(--aparte-font-weight-semibold, 600); margin: 0.6em 0 0.2em; }
|
|
1396
|
+
.aparte-content h2, .segment-content h2 { font-size: var(--aparte-prose-h2-size, 1.25em); font-weight: var(--aparte-font-weight-semibold, 600); margin: 0.5em 0 0.2em; }
|
|
1397
|
+
.aparte-content h3, .segment-content h3 { font-size: var(--aparte-prose-h3-size, 1.1em); font-weight: var(--aparte-font-weight-semibold, 600); margin: 0.4em 0 0.15em; }
|
|
1398
|
+
.aparte-content h4, .segment-content h4,
|
|
1399
|
+
.aparte-content h5, .segment-content h5,
|
|
1400
|
+
.aparte-content h6, .segment-content h6 { font-size: 1em; font-weight: var(--aparte-font-weight-semibold, 600); margin: 0.3em 0 0.1em; }
|
|
1401
|
+
|
|
1402
|
+
.aparte-content ul,
|
|
1403
|
+
.segment-content ul {
|
|
1404
|
+
list-style: disc;
|
|
1405
|
+
padding-left: var(--aparte-prose-list-indent, 1.5em);
|
|
1406
|
+
margin: var(--aparte-prose-list-margin, 0.4em 0);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
.aparte-content ol,
|
|
1410
|
+
.segment-content ol {
|
|
1411
|
+
list-style: decimal;
|
|
1412
|
+
padding-left: var(--aparte-prose-list-indent, 1.5em);
|
|
1413
|
+
margin: var(--aparte-prose-list-margin, 0.4em 0);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.aparte-content li,
|
|
1417
|
+
.segment-content li {
|
|
1418
|
+
margin: var(--aparte-prose-li-margin, 0.15em 0);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
.aparte-content blockquote,
|
|
1422
|
+
.segment-content blockquote {
|
|
1423
|
+
border-left: var(--aparte-prose-blockquote-border-width, 3px) solid var(--aparte-prose-blockquote-border, var(--aparte-border, #e5e7eb));
|
|
1424
|
+
padding-left: 1em;
|
|
1425
|
+
margin: 0.4em 0;
|
|
1426
|
+
color: var(--aparte-text-muted, #6b7280);
|
|
1427
|
+
font-style: italic;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
.aparte-content strong,
|
|
1431
|
+
.segment-content strong {
|
|
1432
|
+
font-weight: var(--aparte-font-weight-semibold, 600);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
.aparte-content em,
|
|
1436
|
+
.segment-content em {
|
|
1437
|
+
font-style: italic;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
.aparte-content code,
|
|
1441
|
+
.segment-content code {
|
|
1442
|
+
font-family: var(--aparte-code-font-family, ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace);
|
|
1443
|
+
font-size: var(--aparte-code-inline-font-size, 0.875em);
|
|
1444
|
+
background: var(--aparte-prose-code-bg, var(--aparte-code-bg, #f3f4f6));
|
|
1445
|
+
padding: 0.1em 0.3em;
|
|
1446
|
+
border-radius: var(--aparte-radius-xs);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
.aparte-content a,
|
|
1450
|
+
.segment-content a {
|
|
1451
|
+
color: var(--aparte-primary, #6366f1);
|
|
1452
|
+
text-decoration: underline;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
.aparte-content hr,
|
|
1456
|
+
.segment-content hr {
|
|
1457
|
+
border: none;
|
|
1458
|
+
border-top: var(--aparte-border-width, 1px) solid var(--aparte-border, #e5e7eb);
|
|
1459
|
+
margin: 0.75em 0;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
/* Thinking */
|
|
1463
|
+
.segment-thinking {
|
|
1464
|
+
/* Understated disclosure: a muted left rail, not a filled card. */
|
|
1465
|
+
border-left: var(--aparte-thinking-rail-width, 2px) solid var(--aparte-thinking-border, #e5e7eb);
|
|
1466
|
+
margin: var(--aparte-space-5, 10px) 0;
|
|
1467
|
+
background: transparent;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
.thinking-header {
|
|
1471
|
+
display: flex;
|
|
1472
|
+
align-items: center;
|
|
1473
|
+
gap: var(--aparte-space-3, 6px);
|
|
1474
|
+
padding: var(--aparte-space-1, 2px) 0 var(--aparte-space-1, 2px) var(--aparte-space-5, 10px);
|
|
1475
|
+
cursor: pointer;
|
|
1476
|
+
user-select: none;
|
|
1477
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1478
|
+
color: var(--aparte-thinking-text, #6b7280);
|
|
1479
|
+
list-style: none;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
.thinking-header::-webkit-details-marker {
|
|
1483
|
+
display: none;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
.thinking-toggle {
|
|
1487
|
+
margin-inline-start: auto;
|
|
1488
|
+
/* Logical property */
|
|
1489
|
+
transition: transform 0.2s;
|
|
1490
|
+
opacity: 0.55;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
details[open] .thinking-toggle {
|
|
1494
|
+
transform: rotate(180deg);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
.thinking-toggle::after {
|
|
1498
|
+
content: '▼';
|
|
1499
|
+
font-size: var(--aparte-thinking-toggle-size, 9px);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
.thinking-content {
|
|
1503
|
+
padding: var(--aparte-space-2, 4px) 0 var(--aparte-space-1, 2px) var(--aparte-space-5, 10px);
|
|
1504
|
+
font-size: var(--aparte-font-size-md, 13px);
|
|
1505
|
+
line-height: var(--aparte-thinking-content-line-height, 1.55);
|
|
1506
|
+
white-space: pre-wrap;
|
|
1507
|
+
color: var(--aparte-thinking-content, #4b5563);
|
|
1508
|
+
background: transparent;
|
|
1509
|
+
max-height: var(--aparte-thinking-content-max-height, 300px);
|
|
1510
|
+
overflow-y: auto;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/* Code */
|
|
1514
|
+
.segment-code {
|
|
1515
|
+
margin: var(--aparte-space-6, 12px) 0;
|
|
1516
|
+
border-radius: var(--aparte-radius-code);
|
|
1517
|
+
overflow: hidden;
|
|
1518
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-code-border, #e5e7eb);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
.code-header {
|
|
1522
|
+
display: flex;
|
|
1523
|
+
align-items: center;
|
|
1524
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1525
|
+
background: var(--aparte-code-header-bg, #f3f4f6);
|
|
1526
|
+
border-bottom: var(--aparte-border-width, 1px) solid var(--aparte-code-border, #e5e7eb);
|
|
1527
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1528
|
+
color: var(--aparte-code-header-text, #4b5563);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
.code-filename {
|
|
1532
|
+
font-weight: var(--aparte-font-weight-semibold, 600);
|
|
1533
|
+
margin-inline-end: auto;
|
|
1534
|
+
/* Logical property: pushes language + copy to the right when filename is present */
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
.code-header-filler {
|
|
1538
|
+
flex: 1;
|
|
1539
|
+
/* No-filename placeholder — keeps language + copy right-aligned */
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
.code-language {
|
|
1543
|
+
margin-inline-end: var(--aparte-space-4, 8px);
|
|
1544
|
+
/* Logical property */
|
|
1545
|
+
text-transform: uppercase;
|
|
1546
|
+
opacity: 0.7;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
.code-copy {
|
|
1550
|
+
background: transparent;
|
|
1551
|
+
border: none;
|
|
1552
|
+
cursor: pointer;
|
|
1553
|
+
padding: var(--aparte-space-2, 4px);
|
|
1554
|
+
border-radius: var(--aparte-radius-sm);
|
|
1555
|
+
color: inherit;
|
|
1556
|
+
display: flex;
|
|
1557
|
+
align-items: center;
|
|
1558
|
+
justify-content: center;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.code-copy:hover {
|
|
1562
|
+
background: var(--aparte-code-copy-hover-bg, rgba(0, 0, 0, 0.05));
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
.code-copy svg {
|
|
1566
|
+
width: var(--aparte-code-copy-icon-size, 14px);
|
|
1567
|
+
height: var(--aparte-code-copy-icon-size, 14px);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
.code-content-wrapper pre {
|
|
1571
|
+
margin: 0;
|
|
1572
|
+
padding: var(--aparte-space-6, 12px);
|
|
1573
|
+
/* Wrap long lines instead of a horizontal scrollbar. `pre-wrap` honours
|
|
1574
|
+
newlines + indentation but soft-wraps overflowing lines; `overflow-wrap:
|
|
1575
|
+
anywhere` breaks unbreakable tokens (long URLs, hashes). Applies to both
|
|
1576
|
+
the plain <pre><code> initial render and the shiki <pre class="shiki">
|
|
1577
|
+
replacement, since both sit inside .code-content-wrapper. */
|
|
1578
|
+
white-space: pre-wrap;
|
|
1579
|
+
overflow-wrap: anywhere;
|
|
1580
|
+
overflow-x: hidden;
|
|
1581
|
+
background: var(--aparte-code-bg, #ffffff);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/* Terminal */
|
|
1585
|
+
.segment-terminal {
|
|
1586
|
+
margin: var(--aparte-space-6, 12px) 0;
|
|
1587
|
+
font-family: var(--aparte-code-font-family, 'Fira Code', 'Monaco', 'Consolas', monospace);
|
|
1588
|
+
font-size: var(--aparte-terminal-font-size, 13px);
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
.terminal-command-block {
|
|
1592
|
+
display: flex;
|
|
1593
|
+
align-items: center;
|
|
1594
|
+
gap: var(--aparte-space-5, 10px);
|
|
1595
|
+
padding: var(--aparte-space-5, 10px) var(--aparte-space-7, 14px);
|
|
1596
|
+
background: var(--aparte-terminal-bg, #1e293b);
|
|
1597
|
+
border-radius: var(--aparte-radius-terminal);
|
|
1598
|
+
color: var(--aparte-terminal-text, #e2e8f0);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
.terminal-icon {
|
|
1602
|
+
flex-shrink: 0;
|
|
1603
|
+
color: var(--aparte-terminal-icon, #64748b);
|
|
1604
|
+
display: flex;
|
|
1605
|
+
align-items: center;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
.terminal-command {
|
|
1609
|
+
flex: 1;
|
|
1610
|
+
word-break: break-all;
|
|
1611
|
+
background: transparent;
|
|
1612
|
+
color: inherit;
|
|
1613
|
+
font-family: inherit;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
.terminal-actions {
|
|
1617
|
+
display: flex;
|
|
1618
|
+
align-items: center;
|
|
1619
|
+
gap: var(--aparte-space-3, 6px);
|
|
1620
|
+
flex-shrink: 0;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
.terminal-run-btn {
|
|
1624
|
+
padding: var(--aparte-space-2, 4px) var(--aparte-space-6, 12px);
|
|
1625
|
+
background: var(--aparte-primary, #6366f1);
|
|
1626
|
+
color: var(--aparte-on-primary, white);
|
|
1627
|
+
border: none;
|
|
1628
|
+
border-radius: var(--aparte-radius-sm);
|
|
1629
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1630
|
+
font-weight: var(--aparte-font-weight-medium, 500);
|
|
1631
|
+
cursor: pointer;
|
|
1632
|
+
transition: background 0.15s;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
.terminal-run-btn:hover {
|
|
1636
|
+
background: var(--aparte-primary-hover, #4f46e5);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
.terminal-copy-btn {
|
|
1640
|
+
width: var(--aparte-terminal-copy-btn-size, 26px);
|
|
1641
|
+
height: var(--aparte-terminal-copy-btn-size, 26px);
|
|
1642
|
+
padding: 0;
|
|
1643
|
+
background: transparent;
|
|
1644
|
+
border: none;
|
|
1645
|
+
color: var(--aparte-terminal-icon, #64748b);
|
|
1646
|
+
cursor: pointer;
|
|
1647
|
+
border-radius: var(--aparte-radius-sm);
|
|
1648
|
+
display: flex;
|
|
1649
|
+
align-items: center;
|
|
1650
|
+
justify-content: center;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
.terminal-copy-btn:hover {
|
|
1654
|
+
background: var(--aparte-terminal-hover, #334155);
|
|
1655
|
+
color: var(--aparte-terminal-text, #e2e8f0);
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
.terminal-running {
|
|
1659
|
+
display: flex;
|
|
1660
|
+
align-items: center;
|
|
1661
|
+
gap: var(--aparte-space-3, 6px);
|
|
1662
|
+
color: var(--aparte-terminal-running, #22c55e);
|
|
1663
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
.terminal-running .spinner {
|
|
1667
|
+
width: var(--aparte-space-6, 12px);
|
|
1668
|
+
height: var(--aparte-space-6, 12px);
|
|
1669
|
+
border: 2px solid currentColor;
|
|
1670
|
+
border-top-color: transparent;
|
|
1671
|
+
border-radius: 50%;
|
|
1672
|
+
animation: aparte-spin 0.8s linear infinite;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
@keyframes aparte-spin {
|
|
1676
|
+
to {
|
|
1677
|
+
transform: rotate(360deg);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
.terminal-output {
|
|
1682
|
+
margin-top: var(--aparte-space-4, 8px);
|
|
1683
|
+
padding: var(--aparte-space-5, 10px) var(--aparte-space-7, 14px);
|
|
1684
|
+
background: var(--aparte-terminal-output-bg, #0f172a);
|
|
1685
|
+
border-radius: var(--aparte-radius-md);
|
|
1686
|
+
color: var(--aparte-terminal-output-text, #94a3b8);
|
|
1687
|
+
white-space: pre-wrap;
|
|
1688
|
+
line-height: var(--aparte-line-height-normal, 1.5);
|
|
1689
|
+
max-height: var(--aparte-terminal-output-max-height, 200px);
|
|
1690
|
+
overflow-y: auto;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
.terminal-error {
|
|
1694
|
+
margin-top: var(--aparte-space-3, 6px);
|
|
1695
|
+
padding: var(--aparte-space-3, 6px) var(--aparte-space-5, 10px);
|
|
1696
|
+
background: var(--aparte-error-bg, #fef2f2);
|
|
1697
|
+
border-radius: var(--aparte-radius-sm);
|
|
1698
|
+
color: var(--aparte-error-text, #dc2626);
|
|
1699
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/* Errored bubble state — the whole message carries `data-error` while it holds
|
|
1703
|
+
an error segment (set by the bubble in _reflectError). Kept subtle by default
|
|
1704
|
+
since the error segment itself is already styled; this is a theming hook —
|
|
1705
|
+
restyle `.aparte-message[data-error]` (or its parts) freely. */
|
|
1706
|
+
.aparte-message[data-error] .aparte-avatar {
|
|
1707
|
+
box-shadow: 0 0 0 2px var(--aparte-error-solid, #dc2626);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
/* Error */
|
|
1711
|
+
.segment-error {
|
|
1712
|
+
display: flex;
|
|
1713
|
+
gap: var(--aparte-space-6, 12px);
|
|
1714
|
+
padding: var(--aparte-space-6, 12px) var(--aparte-space-8, 16px);
|
|
1715
|
+
background: var(--aparte-error-bg, #fef2f2);
|
|
1716
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-error-border, #fecaca);
|
|
1717
|
+
border-left: var(--aparte-error-rail-width, 4px) solid var(--aparte-error-solid, #dc2626);
|
|
1718
|
+
border-radius: var(--aparte-radius-error);
|
|
1719
|
+
margin: var(--aparte-space-6, 12px) 0;
|
|
1720
|
+
color: var(--aparte-error-text, #991b1b);
|
|
1721
|
+
font-family: var(--aparte-font-family, system-ui, sans-serif);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
.error-icon-wrapper {
|
|
1725
|
+
flex-shrink: 0;
|
|
1726
|
+
color: var(--aparte-error-solid, #dc2626);
|
|
1727
|
+
display: flex;
|
|
1728
|
+
align-items: flex-start;
|
|
1729
|
+
padding-top: var(--aparte-space-1, 2px);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
.error-icon-wrapper svg {
|
|
1733
|
+
width: var(--aparte-error-icon-size, 20px);
|
|
1734
|
+
height: var(--aparte-error-icon-size, 20px);
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
.error-content {
|
|
1738
|
+
flex: 1;
|
|
1739
|
+
min-width: 0;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
.error-title {
|
|
1743
|
+
font-weight: var(--aparte-font-weight-semibold, 600);
|
|
1744
|
+
font-size: var(--aparte-font-size-lg, 14px);
|
|
1745
|
+
margin-bottom: var(--aparte-space-2, 4px);
|
|
1746
|
+
color: var(--aparte-error-title, #7f1d1d);
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
.error-message {
|
|
1750
|
+
font-size: var(--aparte-font-size-lg, 14px);
|
|
1751
|
+
line-height: var(--aparte-line-height-normal, 1.5);
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
.error-details {
|
|
1755
|
+
margin-top: var(--aparte-space-4, 8px);
|
|
1756
|
+
padding-top: var(--aparte-space-4, 8px);
|
|
1757
|
+
border-top: var(--aparte-border-width, 1px) solid var(--aparte-error-border, #fecaca);
|
|
1758
|
+
font-family: var(--aparte-code-font-family, monospace);
|
|
1759
|
+
font-size: var(--aparte-font-size-sm, 12px);
|
|
1760
|
+
opacity: 0.9;
|
|
1761
|
+
white-space: pre-wrap;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
/* Progress */
|
|
1765
|
+
.segment-progress {
|
|
1766
|
+
margin: var(--aparte-space-6, 12px) 0;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
.progress-header {
|
|
1770
|
+
display: flex;
|
|
1771
|
+
justify-content: space-between;
|
|
1772
|
+
align-items: center;
|
|
1773
|
+
margin-bottom: var(--aparte-space-2, 4px);
|
|
1774
|
+
color: var(--aparte-progress-label, #374151);
|
|
1775
|
+
font-size: var(--aparte-font-size-lg, 14px);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.progress-bar {
|
|
1779
|
+
height: var(--aparte-space-2, 4px);
|
|
1780
|
+
background: var(--aparte-progress-bar-bg, #e5e7eb);
|
|
1781
|
+
border-radius: var(--aparte-radius-xs);
|
|
1782
|
+
margin-top: var(--aparte-space-4, 8px);
|
|
1783
|
+
overflow: hidden;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
.progress-fill {
|
|
1787
|
+
height: 100%;
|
|
1788
|
+
background: var(--aparte-progress-bar-fill, #6366f1);
|
|
1789
|
+
border-radius: var(--aparte-radius-xs);
|
|
1790
|
+
transition: width 0.3s ease;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
/* File Tree */
|
|
1794
|
+
.segment-file-tree {
|
|
1795
|
+
background: var(--aparte-file-tree-bg, #f8fafc);
|
|
1796
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-file-tree-border, #e2e8f0);
|
|
1797
|
+
border-radius: var(--aparte-radius-file-tree);
|
|
1798
|
+
margin: var(--aparte-space-6, 12px) 0;
|
|
1799
|
+
overflow: hidden;
|
|
1800
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
1801
|
+
font-size: var(--aparte-font-size-md, 13px);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
.file-tree-title {
|
|
1805
|
+
padding: var(--aparte-space-5, 10px) var(--aparte-space-7, 14px);
|
|
1806
|
+
background: var(--aparte-file-tree-header-bg, #f1f5f9);
|
|
1807
|
+
border-bottom: var(--aparte-border-width, 1px) solid var(--aparte-file-tree-border, #e2e8f0);
|
|
1808
|
+
font-weight: var(--aparte-font-weight-medium, 500);
|
|
1809
|
+
color: var(--aparte-file-tree-title, #475569);
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
.file-tree-content {
|
|
1813
|
+
padding: var(--aparte-space-4, 8px) 0;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
.file-node {
|
|
1817
|
+
display: flex;
|
|
1818
|
+
align-items: center;
|
|
1819
|
+
gap: var(--aparte-space-4, 8px);
|
|
1820
|
+
padding: var(--aparte-space-2, 4px) var(--aparte-space-7, 14px);
|
|
1821
|
+
cursor: default;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
.file-node:hover {
|
|
1825
|
+
background: var(--aparte-file-tree-hover, #f1f5f9);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
.file-node.file-status-added .file-name { color: var(--aparte-file-status-added, #16a34a); }
|
|
1829
|
+
.file-node.file-status-modified .file-name { color: var(--aparte-file-status-modified, #0284c7); }
|
|
1830
|
+
.file-node.file-status-deleted .file-name { color: var(--aparte-file-status-deleted, #dc2626); text-decoration: line-through; opacity: 0.7; }
|
|
1831
|
+
|
|
1832
|
+
.file-icon {
|
|
1833
|
+
font-size: var(--aparte-font-size-lg, 14px);
|
|
1834
|
+
flex-shrink: 0;
|
|
1835
|
+
opacity: 0.7;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
1839
|
+
Composer Primitives
|
|
1840
|
+
Headless by design — consumers own layout. These rules provide only the
|
|
1841
|
+
minimum defaults needed for correctness (display, box model, interaction).
|
|
1842
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
1843
|
+
|
|
1844
|
+
aparte-composer {
|
|
1845
|
+
display: block;
|
|
1846
|
+
/* Container-query root — see aparte-chat-viewport. */
|
|
1847
|
+
container-type: inline-size;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
aparte-composer-input {
|
|
1851
|
+
display: block;
|
|
1852
|
+
flex: 1 1 auto;
|
|
1853
|
+
min-width: 0;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
/* Contenteditable editor inside aparte-composer-input */
|
|
1857
|
+
aparte-composer-input .aparte-ci-editor {
|
|
1858
|
+
display: block;
|
|
1859
|
+
width: 100%;
|
|
1860
|
+
min-height: var(--aparte-composer-control-size, 44px);
|
|
1861
|
+
padding: var(--aparte-input-padding-y, 10px) var(--aparte-input-padding-x, 12px);
|
|
1862
|
+
font-size: var(--aparte-input-font-size, 14px);
|
|
1863
|
+
line-height: var(--aparte-input-line-height, 1.5);
|
|
1864
|
+
color: var(--aparte-text);
|
|
1865
|
+
background: transparent;
|
|
1866
|
+
border: none;
|
|
1867
|
+
outline: none;
|
|
1868
|
+
resize: none;
|
|
1869
|
+
white-space: pre-wrap;
|
|
1870
|
+
word-wrap: break-word;
|
|
1871
|
+
overflow-y: hidden;
|
|
1872
|
+
box-sizing: border-box;
|
|
1873
|
+
caret-color: var(--aparte-text);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
/* Placeholder via CSS */
|
|
1877
|
+
aparte-composer-input .aparte-ci-editor:empty::before {
|
|
1878
|
+
content: attr(data-placeholder);
|
|
1879
|
+
color: var(--aparte-input-placeholder, var(--aparte-text-muted, #9ca3af));
|
|
1880
|
+
pointer-events: none;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
aparte-composer-input .aparte-ci-editor[aria-disabled="true"] {
|
|
1884
|
+
opacity: 0.6;
|
|
1885
|
+
cursor: not-allowed;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
aparte-composer-send {
|
|
1889
|
+
display: contents;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
aparte-composer-cancel {
|
|
1893
|
+
display: contents;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
/* ── Attachment chips list ── */
|
|
1897
|
+
aparte-composer-attachments {
|
|
1898
|
+
display: flex;
|
|
1899
|
+
flex-wrap: wrap;
|
|
1900
|
+
gap: var(--aparte-space-3, 6px);
|
|
1901
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1902
|
+
width: 100%;
|
|
1903
|
+
box-sizing: border-box;
|
|
1904
|
+
border-bottom: var(--aparte-border-width, 1px) solid var(--aparte-border);
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
aparte-composer-attachments[hidden] {
|
|
1908
|
+
display: none;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/* Composer attachment strip — lays out the thumbnail tiles (.aparte-thumb). */
|
|
1912
|
+
aparte-composer-attachments {
|
|
1913
|
+
display: flex;
|
|
1914
|
+
flex-wrap: wrap;
|
|
1915
|
+
gap: var(--aparte-space-3, 6px);
|
|
1916
|
+
--aparte-attachment-image-size: 56px;
|
|
1917
|
+
/* Many attachments → cap the height and scroll. */
|
|
1918
|
+
max-height: var(--aparte-attachments-max-height, 140px);
|
|
1919
|
+
overflow-y: auto;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
/* ── Add attachment button ── */
|
|
1923
|
+
aparte-composer-add-attachment {
|
|
1924
|
+
display: contents;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
/* ── Generic action button ── */
|
|
1928
|
+
aparte-composer-action {
|
|
1929
|
+
display: contents;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
/* ── Drag-over state on root ── */
|
|
1933
|
+
aparte-composer.is-dragover .aparte-composer-shell {
|
|
1934
|
+
outline: var(--aparte-focus-outline-width, 2px) dashed var(--aparte-primary);
|
|
1935
|
+
outline-offset: -2px;
|
|
1936
|
+
border-radius: var(--aparte-radius-input, 12px);
|
|
1937
|
+
}
|
|
1938
|
+
/* fallback: no shell */
|
|
1939
|
+
aparte-composer.is-dragover:not(:has(.aparte-composer-shell)) {
|
|
1940
|
+
outline: var(--aparte-focus-outline-width, 2px) dashed var(--aparte-primary);
|
|
1941
|
+
outline-offset: -2px;
|
|
1942
|
+
border-radius: var(--aparte-radius-input, 12px);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
1946
|
+
Composer Layout Helpers (opt-in, not required)
|
|
1947
|
+
Use these classes when you want the composer look out of the box.
|
|
1948
|
+
|
|
1949
|
+
<aparte-composer>
|
|
1950
|
+
<div class="aparte-composer-shell">
|
|
1951
|
+
<aparte-composer-attachments></aparte-composer-attachments>
|
|
1952
|
+
<div class="aparte-composer-row">
|
|
1953
|
+
<aparte-composer-add-attachment></aparte-composer-add-attachment>
|
|
1954
|
+
<aparte-composer-input></aparte-composer-input>
|
|
1955
|
+
<aparte-composer-send></aparte-composer-send>
|
|
1956
|
+
</div>
|
|
1957
|
+
</div>
|
|
1958
|
+
</aparte-composer>
|
|
1959
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
1960
|
+
|
|
1961
|
+
/* Outer shell — visual border + radius. Mirrors .aparte-input-wrapper */
|
|
1962
|
+
.aparte-composer-shell {
|
|
1963
|
+
background: var(--aparte-input-bg, var(--aparte-surface-1));
|
|
1964
|
+
border: var(--aparte-border-width, 1px) solid var(--aparte-input-border, var(--aparte-border));
|
|
1965
|
+
border-radius: var(--aparte-radius-input, 12px);
|
|
1966
|
+
max-width: var(--aparte-message-max-width, 800px);
|
|
1967
|
+
margin: 0 auto;
|
|
1968
|
+
width: 100%;
|
|
1969
|
+
box-sizing: border-box;
|
|
1970
|
+
transition: border-color 0.2s;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
.aparte-composer-shell:focus-within {
|
|
1974
|
+
border-color: var(--aparte-primary);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/* Inner row — flex container for input + buttons */
|
|
1978
|
+
.aparte-composer-row {
|
|
1979
|
+
display: flex;
|
|
1980
|
+
align-items: flex-end;
|
|
1981
|
+
gap: var(--aparte-space-4, 8px);
|
|
1982
|
+
padding: var(--aparte-space-4, 8px) var(--aparte-space-6, 12px);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/* Action buttons sized to the input's single-line height — BOTH derive from
|
|
1986
|
+
--aparte-composer-control-size (default 44px), so a theme resizes the whole
|
|
1987
|
+
composer control set with ONE variable and alignment holds. Combined with
|
|
1988
|
+
the row's `align-items: flex-end` this makes the buttons read as vertically
|
|
1989
|
+
centered against a single line of text, and keeps them anchored to the
|
|
1990
|
+
bottom once the input grows multi-line — no magic margins. */
|
|
1991
|
+
.aparte-composer-row button {
|
|
1992
|
+
width: var(--aparte-composer-control-size, 44px);
|
|
1993
|
+
height: var(--aparte-composer-control-size, 44px);
|
|
1994
|
+
box-sizing: border-box;
|
|
1995
|
+
flex-shrink: 0;
|
|
1996
|
+
display: flex;
|
|
1997
|
+
align-items: center;
|
|
1998
|
+
justify-content: center;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/* Footer row below the input row (model selector etc.) */
|
|
2002
|
+
.aparte-composer-footer {
|
|
2003
|
+
display: flex;
|
|
2004
|
+
align-items: center;
|
|
2005
|
+
gap: var(--aparte-space-4, 8px);
|
|
2006
|
+
padding: var(--aparte-space-3, 6px) var(--aparte-space-6, 12px);
|
|
2007
|
+
border-top: var(--aparte-border-width, 1px) solid var(--aparte-border);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
.aparte-composer-footer:empty {
|
|
2011
|
+
display: none;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/* Cancel/dictate button — same visual style as action buttons */
|
|
2015
|
+
aparte-composer-cancel .aparte-cc-button[hidden],
|
|
2016
|
+
aparte-composer-dictate .aparte-cd-button[hidden] {
|
|
2017
|
+
display: none !important;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
aparte-composer-cancel .aparte-cc-button,
|
|
2021
|
+
aparte-composer-dictate .aparte-cd-button {
|
|
2022
|
+
background: transparent;
|
|
2023
|
+
border: none;
|
|
2024
|
+
color: var(--aparte-neutral, #6b7280);
|
|
2025
|
+
padding: var(--aparte-space-3, 6px);
|
|
2026
|
+
border-radius: var(--aparte-radius-action-btn, 6px);
|
|
2027
|
+
cursor: pointer;
|
|
2028
|
+
display: flex;
|
|
2029
|
+
align-items: center;
|
|
2030
|
+
justify-content: center;
|
|
2031
|
+
flex-shrink: 0;
|
|
2032
|
+
transition: color 0.15s, background 0.15s;
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
aparte-composer-cancel .aparte-cc-button:hover,
|
|
2036
|
+
aparte-composer-dictate .aparte-cd-button:hover {
|
|
2037
|
+
color: var(--aparte-text);
|
|
2038
|
+
background: var(--aparte-surface-2);
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
2042
|
+
Opt-in "centered composer when empty" — add the `--auto-center` modifier
|
|
2043
|
+
(the wrappers do this from their `centerWhenEmpty` prop). Consumers that never
|
|
2044
|
+
opt in keep just the base layout above.
|
|
2045
|
+
|
|
2046
|
+
Empty → the [welcome + composer] group sits vertically centered.
|
|
2047
|
+
Active → on the first message the list grows and the composer slides to the
|
|
2048
|
+
bottom (~0.3s). Only `flex-grow` toggles between the two states
|
|
2049
|
+
(flex-basis/height stay constant) so the transition slides instead
|
|
2050
|
+
of snapping. Scoped to `.aparte-viewport--framework` so the native
|
|
2051
|
+
(vanilla) viewport is never touched.
|
|
2052
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
2053
|
+
|
|
2054
|
+
.aparte-chat-container--auto-center {
|
|
2055
|
+
display: flex;
|
|
2056
|
+
flex-direction: column;
|
|
2057
|
+
height: 100%;
|
|
2058
|
+
min-height: 0;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
.aparte-chat-container--auto-center aparte-chat-viewport.aparte-viewport--framework {
|
|
2062
|
+
flex: 1 1 auto;
|
|
2063
|
+
min-height: 0;
|
|
2064
|
+
height: auto;
|
|
2065
|
+
transition: flex-grow 0.3s ease; /* the "slide to bottom" on first message */
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
.aparte-chat-container--auto-center aparte-composer {
|
|
2069
|
+
flex: 0 0 auto;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
/* Empty delta — a wrapper sets [data-aparte-empty] only while centerWhenEmpty is
|
|
2073
|
+
on AND the message list is empty. `justify-content` flips instantly (not an
|
|
2074
|
+
animatable property) — fine, it only differs between the two steady states. */
|
|
2075
|
+
.aparte-chat-container--auto-center[data-aparte-empty] {
|
|
2076
|
+
justify-content: center;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.aparte-chat-container--auto-center[data-aparte-empty]
|
|
2080
|
+
aparte-chat-viewport.aparte-viewport--framework {
|
|
2081
|
+
flex-grow: 0;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
/* The pre-existing reduced-motion guard only matches `aparte-chat-viewport *`
|
|
2085
|
+
(descendants), not the element itself — so the transition above needs its
|
|
2086
|
+
own guard. */
|
|
2087
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2088
|
+
.aparte-chat-container--auto-center
|
|
2089
|
+
aparte-chat-viewport.aparte-viewport--framework {
|
|
2090
|
+
transition-duration: 0.01ms;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
/* =========================================
|
|
2095
|
+
aparte-conversation-list
|
|
2096
|
+
========================================= */
|
|
2097
|
+
|
|
2098
|
+
aparte-conversation-list {
|
|
2099
|
+
display: flex;
|
|
2100
|
+
flex-direction: column;
|
|
2101
|
+
gap: var(--aparte-conv-list-gap, 2px);
|
|
2102
|
+
overflow-y: auto;
|
|
2103
|
+
overflow-x: hidden;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
.aparte-conv-item {
|
|
2107
|
+
display: flex;
|
|
2108
|
+
align-items: center;
|
|
2109
|
+
gap: var(--aparte-conv-item-gap, 6px);
|
|
2110
|
+
padding: var(--aparte-conv-item-padding, 7px 10px);
|
|
2111
|
+
border-radius: var(--aparte-conv-item-radius, 6px);
|
|
2112
|
+
cursor: pointer;
|
|
2113
|
+
min-width: 0;
|
|
2114
|
+
color: var(--aparte-conv-item-color, var(--aparte-text-muted));
|
|
2115
|
+
font-size: var(--aparte-conv-item-font-size, 0.8125rem);
|
|
2116
|
+
font-family: var(--aparte-font-family, system-ui, -apple-system, sans-serif);
|
|
2117
|
+
transition: background 0.12s;
|
|
2118
|
+
outline: none;
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
.aparte-conv-item:hover {
|
|
2122
|
+
background: var(--aparte-conv-item-bg-hover, var(--aparte-surface-3));
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
.aparte-conv-item:focus-visible {
|
|
2126
|
+
outline: var(--aparte-focus-outline-width, 2px) solid var(--aparte-primary);
|
|
2127
|
+
outline-offset: -2px;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
.aparte-conv-item:hover .aparte-conv-item__delete {
|
|
2131
|
+
opacity: 1;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
.aparte-conv-item:hover .aparte-conv-item__archive {
|
|
2135
|
+
opacity: 1;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
/* Keyboard access (WCAG 2.1.1): the archive/delete actions are opacity:0 until
|
|
2139
|
+
hover, which would hide keyboard focus. Reveal + ring them on focus. */
|
|
2140
|
+
.aparte-conv-item:focus-within .aparte-conv-item__archive,
|
|
2141
|
+
.aparte-conv-item:focus-within .aparte-conv-item__delete {
|
|
2142
|
+
opacity: 1;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
.aparte-conv-item__archive:focus-visible,
|
|
2146
|
+
.aparte-conv-item__delete:focus-visible {
|
|
2147
|
+
opacity: 1;
|
|
2148
|
+
outline: var(--aparte-focus-outline-width, 2px) solid var(--aparte-primary);
|
|
2149
|
+
outline-offset: -2px;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
.aparte-conv-item--active {
|
|
2153
|
+
background: var(--aparte-conv-item-bg-active, var(--aparte-surface-3));
|
|
2154
|
+
color: var(--aparte-conv-item-color-active, var(--aparte-text));
|
|
2155
|
+
font-weight: var(--aparte-conv-item-font-weight-active, 500);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
.aparte-conv-item--active .aparte-conv-item__delete {
|
|
2159
|
+
opacity: 0;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
.aparte-conv-item--active .aparte-conv-item__archive {
|
|
2163
|
+
opacity: 0;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
.aparte-conv-item__title {
|
|
2167
|
+
flex: 1;
|
|
2168
|
+
white-space: nowrap;
|
|
2169
|
+
overflow: hidden;
|
|
2170
|
+
text-overflow: ellipsis;
|
|
2171
|
+
min-width: 0;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
.aparte-conv-item__delete {
|
|
2175
|
+
flex-shrink: 0;
|
|
2176
|
+
opacity: 0;
|
|
2177
|
+
display: flex;
|
|
2178
|
+
align-items: center;
|
|
2179
|
+
justify-content: center;
|
|
2180
|
+
width: var(--aparte-conv-action-btn-size, 20px);
|
|
2181
|
+
height: var(--aparte-conv-action-btn-size, 20px);
|
|
2182
|
+
border: none;
|
|
2183
|
+
background: none;
|
|
2184
|
+
color: var(--aparte-conv-delete-color, var(--aparte-text-muted));
|
|
2185
|
+
border-radius: var(--aparte-conv-delete-radius, var(--aparte-radius-sm));
|
|
2186
|
+
cursor: pointer;
|
|
2187
|
+
padding: 0;
|
|
2188
|
+
transition: opacity 0.12s, background 0.12s, color 0.12s;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
.aparte-conv-item__delete:hover {
|
|
2192
|
+
background: var(--aparte-conv-delete-bg-hover, var(--aparte-error));
|
|
2193
|
+
color: var(--aparte-conv-delete-color-hover, var(--aparte-text-inverse));
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
.aparte-conv-item__archive {
|
|
2197
|
+
flex-shrink: 0;
|
|
2198
|
+
opacity: 0;
|
|
2199
|
+
display: flex;
|
|
2200
|
+
align-items: center;
|
|
2201
|
+
justify-content: center;
|
|
2202
|
+
width: var(--aparte-conv-action-btn-size, 20px);
|
|
2203
|
+
height: var(--aparte-conv-action-btn-size, 20px);
|
|
2204
|
+
border: none;
|
|
2205
|
+
background: none;
|
|
2206
|
+
color: var(--aparte-conv-archive-color, var(--aparte-text-muted));
|
|
2207
|
+
border-radius: var(--aparte-conv-archive-radius, var(--aparte-radius-sm));
|
|
2208
|
+
cursor: pointer;
|
|
2209
|
+
padding: 0;
|
|
2210
|
+
transition: opacity 0.12s, background 0.12s, color 0.12s;
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
.aparte-conv-item__archive:hover {
|
|
2214
|
+
background: var(--aparte-conv-archive-bg-hover, var(--aparte-surface-4, var(--aparte-surface-3)));
|
|
2215
|
+
color: var(--aparte-conv-archive-color-hover, var(--aparte-text));
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
.aparte-conv-item--archived .aparte-conv-item__title {
|
|
2219
|
+
font-style: italic;
|
|
2220
|
+
opacity: 0.85;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
/* =========================================
|
|
2224
|
+
Provider-HTML overflow guards
|
|
2225
|
+
========================================= */
|
|
2226
|
+
|
|
2227
|
+
/* Markdown providers inject arbitrary HTML into .segment-text, and the bubble
|
|
2228
|
+
clips overflow (`aparte-chat-bubble { overflow: hidden }`) — without these
|
|
2229
|
+
guards a wide image or table is silently cut at the bubble edge. */
|
|
2230
|
+
.segment-text img {
|
|
2231
|
+
max-width: 100%;
|
|
2232
|
+
height: auto;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
.segment-text table {
|
|
2236
|
+
display: block;
|
|
2237
|
+
max-width: 100%;
|
|
2238
|
+
overflow-x: auto;
|
|
2239
|
+
border-collapse: collapse;
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
/* =========================================
|
|
2243
|
+
Adaptive layout (container width + input modality)
|
|
2244
|
+
========================================= */
|
|
2245
|
+
|
|
2246
|
+
/* Narrow containers (embedded widgets, mobile) — tighter chrome. The theming
|
|
2247
|
+
variables are defined at :root, so `var(x, fallback)` fallbacks can never
|
|
2248
|
+
fire — instead each rule REASSIGNS the variable at the element, the same
|
|
2249
|
+
per-context pattern .aparte-attachments already uses. To retheme the narrow
|
|
2250
|
+
state, override these variables inside your own @container block. Browsers
|
|
2251
|
+
without container-query support keep the wide defaults. */
|
|
2252
|
+
@container (max-width: 520px) {
|
|
2253
|
+
.aparte-message {
|
|
2254
|
+
--aparte-message-padding: var(--aparte-space-6, 12px) var(--aparte-space-4, 8px);
|
|
2255
|
+
--aparte-message-gap: var(--aparte-space-4, 8px);
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
.aparte-avatar {
|
|
2259
|
+
--aparte-avatar-size: 24px;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
.aparte-messages-wrapper {
|
|
2263
|
+
--aparte-viewport-padding: var(--aparte-space-6, 12px) var(--aparte-space-4, 8px);
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
.aparte-composer-row {
|
|
2267
|
+
padding: var(--aparte-space-4, 8px);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
/* Coarse pointers (touch) — comfortable hit areas. */
|
|
2272
|
+
@media (pointer: coarse) {
|
|
2273
|
+
.aparte-scroll-btn {
|
|
2274
|
+
--aparte-scroll-btn-size: var(--aparte-touch-target-size, 44px);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
.aparte-send-button {
|
|
2278
|
+
--aparte-send-btn-size: var(--aparte-touch-target-size, 44px);
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
.aparte-action-button {
|
|
2282
|
+
--aparte-input-action-btn-size: var(--aparte-touch-target-size, 44px);
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
/* Hover cannot reveal these on touch — keep them visible and tappable. */
|
|
2286
|
+
.aparte-conv-item__delete,
|
|
2287
|
+
.aparte-conv-item__archive {
|
|
2288
|
+
opacity: 1;
|
|
2289
|
+
--aparte-conv-action-btn-size: 28px;
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
/**
|
|
2293
|
+
* Aparte Select CSS
|
|
2294
|
+
* Stylable via CSS variables
|
|
2295
|
+
*/
|
|
2296
|
+
|
|
2297
|
+
aparte-select {
|
|
2298
|
+
display: inline-block;
|
|
2299
|
+
position: relative;
|
|
2300
|
+
min-width: 200px;
|
|
2301
|
+
font-family: var(--aparte-font-family, inherit);
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
/* Trigger */
|
|
2305
|
+
.aparte-select-trigger {
|
|
2306
|
+
display: flex;
|
|
2307
|
+
align-items: center;
|
|
2308
|
+
justify-content: space-between;
|
|
2309
|
+
gap: 0.5rem;
|
|
2310
|
+
padding: 0.5rem 0.75rem;
|
|
2311
|
+
background: var(--aparte-select-bg, var(--aparte-surface-1, #fff));
|
|
2312
|
+
border: 1px solid var(--aparte-select-border, var(--aparte-border, #e2e8f0));
|
|
2313
|
+
border-radius: var(--aparte-select-radius, 0.5rem);
|
|
2314
|
+
cursor: pointer;
|
|
2315
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
.aparte-select-trigger:hover {
|
|
2319
|
+
border-color: var(--aparte-select-border-hover, var(--aparte-primary, #3b82f6));
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
.aparte-select-trigger:focus {
|
|
2323
|
+
outline: none;
|
|
2324
|
+
border-color: var(--aparte-select-border-focus, var(--aparte-primary, #3b82f6));
|
|
2325
|
+
box-shadow: 0 0 0 2px var(--aparte-select-ring, rgba(59, 130, 246, 0.2));
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
aparte-select[disabled] .aparte-select-trigger {
|
|
2329
|
+
opacity: 0.5;
|
|
2330
|
+
cursor: not-allowed;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
.aparte-select-label {
|
|
2334
|
+
flex: 1;
|
|
2335
|
+
overflow: hidden;
|
|
2336
|
+
text-overflow: ellipsis;
|
|
2337
|
+
white-space: nowrap;
|
|
2338
|
+
color: var(--aparte-select-text, var(--aparte-text, #1e293b));
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
.aparte-select-chevron {
|
|
2342
|
+
flex-shrink: 0;
|
|
2343
|
+
color: var(--aparte-select-chevron, var(--aparte-text-muted, #94a3b8));
|
|
2344
|
+
transition: transform 0.2s;
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
aparte-select[open] .aparte-select-chevron {
|
|
2348
|
+
transform: rotate(180deg);
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
/* Dropdown — position:fixed to escape overflow:hidden ancestors */
|
|
2352
|
+
.aparte-select-dropdown {
|
|
2353
|
+
position: fixed;
|
|
2354
|
+
/* top / left / width are set dynamically by _updatePosition() */
|
|
2355
|
+
background: var(--aparte-select-dropdown-bg, var(--aparte-surface-1, #fff));
|
|
2356
|
+
border: 1px solid var(--aparte-select-border, var(--aparte-border, #e2e8f0));
|
|
2357
|
+
border-radius: var(--aparte-select-radius, 0.5rem);
|
|
2358
|
+
box-shadow: var(--aparte-select-shadow, 0 4px 12px rgba(0, 0, 0, 0.1));
|
|
2359
|
+
z-index: var(--aparte-select-z, 1000);
|
|
2360
|
+
max-height: 300px;
|
|
2361
|
+
overflow: auto;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
.aparte-select-dropdown[hidden] {
|
|
2365
|
+
display: none;
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
/* Search */
|
|
2369
|
+
.aparte-select-search {
|
|
2370
|
+
display: block;
|
|
2371
|
+
width: 100%;
|
|
2372
|
+
padding: 0.5rem 0.75rem;
|
|
2373
|
+
border: none;
|
|
2374
|
+
border-bottom: 1px solid var(--aparte-border, #e2e8f0);
|
|
2375
|
+
background: transparent;
|
|
2376
|
+
font-size: inherit;
|
|
2377
|
+
font-family: inherit;
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
.aparte-select-search:focus {
|
|
2381
|
+
outline: none;
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
/* Options container */
|
|
2385
|
+
.aparte-select-options {
|
|
2386
|
+
padding: 0.25rem;
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
/* Option */
|
|
2390
|
+
aparte-option {
|
|
2391
|
+
display: flex;
|
|
2392
|
+
align-items: center;
|
|
2393
|
+
justify-content: space-between;
|
|
2394
|
+
padding: 0.5rem 0.75rem;
|
|
2395
|
+
border-radius: 0.25rem;
|
|
2396
|
+
cursor: pointer;
|
|
2397
|
+
transition: background-color 0.1s;
|
|
2398
|
+
color: var(--aparte-select-text, var(--aparte-text, #1e293b));
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
aparte-option:hover {
|
|
2402
|
+
background: var(--aparte-select-option-hover, var(--aparte-surface-2, #f1f5f9));
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
/* Keyboard-active option (roving highlight driven by aria-activedescendant).
|
|
2406
|
+
Distinct from :hover so keyboard users get an unambiguous focus indicator. */
|
|
2407
|
+
aparte-option[data-active] {
|
|
2408
|
+
background: var(--aparte-select-option-hover, var(--aparte-surface-2, #f1f5f9));
|
|
2409
|
+
box-shadow: inset 0 0 0 2px var(--aparte-primary, #3b82f6);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
aparte-option[selected] {
|
|
2413
|
+
background: var(--aparte-select-option-selected, var(--aparte-primary, #3b82f6));
|
|
2414
|
+
color: var(--aparte-select-option-selected-text, #fff);
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
aparte-option[disabled] {
|
|
2418
|
+
opacity: 0.5;
|
|
2419
|
+
cursor: not-allowed;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
/* Status dot injected by AparteOption when data-status is set */
|
|
2423
|
+
.aparte-status-dot {
|
|
2424
|
+
width: 8px;
|
|
2425
|
+
height: 8px;
|
|
2426
|
+
border-radius: 50%;
|
|
2427
|
+
flex-shrink: 0;
|
|
2428
|
+
margin-left: 8px;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
.aparte-status-dot[data-status="ready"] {
|
|
2432
|
+
background-color: #22c55e;
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
.aparte-status-dot[data-status="cached"] {
|
|
2436
|
+
background-color: #f59e0b;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
.aparte-status-dot[data-status="not-downloaded"] {
|
|
2440
|
+
background-color: var(--aparte-border, #94a3b8);
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
/* Optgroup */
|
|
2444
|
+
aparte-optgroup {
|
|
2445
|
+
display: block;
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
.aparte-optgroup-header {
|
|
2449
|
+
display: flex;
|
|
2450
|
+
align-items: center;
|
|
2451
|
+
justify-content: space-between;
|
|
2452
|
+
padding: 0.5rem 0.75rem;
|
|
2453
|
+
font-size: 0.75rem;
|
|
2454
|
+
font-weight: 600;
|
|
2455
|
+
text-transform: uppercase;
|
|
2456
|
+
letter-spacing: 0.05em;
|
|
2457
|
+
color: var(--aparte-text-muted, #94a3b8);
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
.aparte-optgroup-chevron {
|
|
2461
|
+
width: 0;
|
|
2462
|
+
height: 0;
|
|
2463
|
+
border-left: 4px solid transparent;
|
|
2464
|
+
border-right: 4px solid transparent;
|
|
2465
|
+
border-top: 5px solid currentColor;
|
|
2466
|
+
transition: transform 0.2s;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
aparte-optgroup[collapsed] .aparte-optgroup-chevron {
|
|
2470
|
+
transform: rotate(-90deg);
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
/* Dark mode */
|
|
2474
|
+
[data-aparte-theme="dark"] aparte-select .aparte-select-trigger,
|
|
2475
|
+
[data-aparte-theme="dark"] aparte-select .aparte-select-dropdown {
|
|
2476
|
+
background: var(--aparte-select-bg, var(--aparte-surface-1, #1e293b));
|
|
2477
|
+
border-color: var(--aparte-select-border, var(--aparte-border, #334155));
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
[data-aparte-theme="dark"] aparte-option:hover {
|
|
2481
|
+
background: var(--aparte-select-option-hover, var(--aparte-surface-2, #334155));
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
.aparte-optgroup-loader {
|
|
2485
|
+
padding: 0.5rem 0.75rem;
|
|
2486
|
+
font-size: 0.75rem;
|
|
2487
|
+
color: var(--aparte-text-muted, #94a3b8);
|
|
2488
|
+
font-style: italic;
|
|
2489
|
+
display: flex;
|
|
2490
|
+
align-items: center;
|
|
2491
|
+
gap: 0.5rem;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
.aparte-spinner-small {
|
|
2495
|
+
width: 12px;
|
|
2496
|
+
height: 12px;
|
|
2497
|
+
border: 2px solid currentColor;
|
|
2498
|
+
border-top-color: transparent;
|
|
2499
|
+
border-radius: 50%;
|
|
2500
|
+
animation: aparte-spin 0.6s linear infinite;
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
@keyframes aparte-spin {
|
|
2504
|
+
to {
|
|
2505
|
+
transform: rotate(360deg);
|
|
2506
|
+
}
|
|
2507
|
+
}/**
|
|
2508
|
+
* AparteProgressSpinner — CSS
|
|
2509
|
+
*
|
|
2510
|
+
* All colors are driven by CSS custom properties so consumers can theme freely.
|
|
2511
|
+
* The `color` property on the element controls both fill and track by default.
|
|
2512
|
+
*/
|
|
2513
|
+
|
|
2514
|
+
aparte-progress-spinner {
|
|
2515
|
+
display: inline-flex;
|
|
2516
|
+
align-items: center;
|
|
2517
|
+
justify-content: center;
|
|
2518
|
+
width: var(--aparte-spinner-size, 14px);
|
|
2519
|
+
height: var(--aparte-spinner-size, 14px);
|
|
2520
|
+
flex-shrink: 0;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
aparte-progress-spinner svg {
|
|
2524
|
+
width: 100%;
|
|
2525
|
+
height: 100%;
|
|
2526
|
+
/* Start arc from 12 o'clock */
|
|
2527
|
+
transform: rotate(-90deg);
|
|
2528
|
+
transform-origin: center;
|
|
2529
|
+
overflow: visible;
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
.aparte-spinner-track {
|
|
2533
|
+
fill: none;
|
|
2534
|
+
stroke: var(--aparte-spinner-track, color-mix(in srgb, currentColor 15%, transparent));
|
|
2535
|
+
stroke-width: var(--aparte-spinner-stroke, 2.5);
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
.aparte-spinner-fill {
|
|
2539
|
+
fill: none;
|
|
2540
|
+
stroke: var(--aparte-spinner-color, currentColor);
|
|
2541
|
+
stroke-width: var(--aparte-spinner-stroke, 2.5);
|
|
2542
|
+
stroke-linecap: round;
|
|
2543
|
+
transition: stroke-dashoffset 0.25s ease;
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
/* Indeterminate: rotate the whole SVG continuously */
|
|
2547
|
+
aparte-progress-spinner:not([value]) svg {
|
|
2548
|
+
animation: aparte-spinner-rotate 0.9s linear infinite;
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
@keyframes aparte-spinner-rotate {
|
|
2552
|
+
from { transform: rotate(-90deg); }
|
|
2553
|
+
to { transform: rotate(270deg); }
|
|
2554
|
+
}
|