@devicai/ui 0.16.0 → 0.18.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.
@@ -28,7 +28,7 @@ function pickMimeType(preferred) {
28
28
  * cancelling the animation frame on stop/cancel/unmount.
29
29
  */
30
30
  function useSpeechRecording(options = {}) {
31
- const { bars = 5, mimeType } = options;
31
+ const { bars = 5, mimeType, autoStop = true, autoStopSilenceMs = 1000, autoStopCountdownMs = 1000, autoStopSilenceRatio = 0.1, autoStopSilenceLevel = 0.02, autoStopSpeechLevel = 0.12, onAutoStop, } = options;
32
32
  const isSupported = typeof navigator !== 'undefined' &&
33
33
  !!navigator.mediaDevices?.getUserMedia &&
34
34
  typeof MediaRecorder !== 'undefined';
@@ -36,6 +36,8 @@ function useSpeechRecording(options = {}) {
36
36
  const [levels, setLevels] = React.useState(() => new Array(bars).fill(0));
37
37
  const [durationMs, setDurationMs] = React.useState(0);
38
38
  const [error, setError] = React.useState(null);
39
+ const [isAutoStopping, setIsAutoStopping] = React.useState(false);
40
+ const [autoStopProgress, setAutoStopProgress] = React.useState(1);
39
41
  const mediaRecorderRef = React.useRef(null);
40
42
  const streamRef = React.useRef(null);
41
43
  const chunksRef = React.useRef([]);
@@ -46,6 +48,108 @@ function useSpeechRecording(options = {}) {
46
48
  const accumulatedRef = React.useRef(0);
47
49
  const stopResolveRef = React.useRef(null);
48
50
  const discardRef = React.useRef(false);
51
+ // --- Auto-stop (silence detection) state, all kept in refs so the rAF loop
52
+ // reads it without forcing `tick` to re-subscribe. ---
53
+ const hasSpeechRef = React.useRef(false); // user has spoken at least once
54
+ const loudestRef = React.useRef(0); // loudest peak seen (reference for adaptive silence)
55
+ const silenceStartRef = React.useRef(null); // when current silence began
56
+ const autoStopStartRef = React.useRef(null); // when the countdown started
57
+ const autoStopFiredRef = React.useRef(false); // guard against re-firing before stop
58
+ // Latest-config ref so the loop always sees fresh thresholds and callback.
59
+ const autoStopCfgRef = React.useRef({
60
+ autoStop,
61
+ autoStopSilenceMs,
62
+ autoStopCountdownMs,
63
+ autoStopSilenceRatio,
64
+ autoStopSilenceLevel,
65
+ autoStopSpeechLevel,
66
+ onAutoStop,
67
+ });
68
+ autoStopCfgRef.current = {
69
+ autoStop,
70
+ autoStopSilenceMs,
71
+ autoStopCountdownMs,
72
+ autoStopSilenceRatio,
73
+ autoStopSilenceLevel,
74
+ autoStopSpeechLevel,
75
+ onAutoStop,
76
+ };
77
+ // Reset all auto-stop tracking. `keepSpeech` preserves the "user has spoken"
78
+ // flag across a pause/resume so it doesn't re-arm from scratch.
79
+ const resetAutoStop = React.useCallback((keepSpeech = false) => {
80
+ if (!keepSpeech) {
81
+ hasSpeechRef.current = false;
82
+ loudestRef.current = 0;
83
+ }
84
+ silenceStartRef.current = null;
85
+ autoStopStartRef.current = null;
86
+ autoStopFiredRef.current = false;
87
+ setIsAutoStopping(false);
88
+ setAutoStopProgress(1);
89
+ }, []);
90
+ // Evaluate the current peak amplitude against the silence/speech thresholds
91
+ // and drive the auto-stop countdown. Called once per animation frame.
92
+ const evaluateAutoStop = React.useCallback((peak) => {
93
+ const cfg = autoStopCfgRef.current;
94
+ if (!cfg.autoStop || autoStopFiredRef.current)
95
+ return;
96
+ const now = Date.now();
97
+ // 1) Arm only once a real voice peak (absolute floor) has been heard. This
98
+ // also seeds the reference loudness so ambient noise alone can't arm it.
99
+ if (!hasSpeechRef.current) {
100
+ if (peak >= cfg.autoStopSpeechLevel) {
101
+ hasSpeechRef.current = true;
102
+ loudestRef.current = peak;
103
+ }
104
+ return;
105
+ }
106
+ // 2) Track the loudest voice so the silence threshold scales with how loud
107
+ // the user actually speaks (robust to ambient noise).
108
+ if (peak > loudestRef.current)
109
+ loudestRef.current = peak;
110
+ // 3) Adaptive thresholds: silence = ratio of the loudest voice (with an
111
+ // absolute floor); activity sits above it for hysteresis, so background
112
+ // noise between the two doesn't keep cancelling the countdown.
113
+ const silenceThreshold = Math.max(cfg.autoStopSilenceLevel, cfg.autoStopSilenceRatio * loudestRef.current);
114
+ const activityThreshold = silenceThreshold * 1.8;
115
+ if (peak >= activityThreshold) {
116
+ // Talking again: reset silence and cancel any pending countdown.
117
+ silenceStartRef.current = null;
118
+ if (autoStopStartRef.current !== null) {
119
+ autoStopStartRef.current = null;
120
+ setIsAutoStopping(false);
121
+ setAutoStopProgress(1);
122
+ }
123
+ return;
124
+ }
125
+ if (peak <= silenceThreshold) {
126
+ if (silenceStartRef.current === null)
127
+ silenceStartRef.current = now;
128
+ if (autoStopStartRef.current === null) {
129
+ // Waiting out the silence window before the countdown begins.
130
+ if (now - silenceStartRef.current >= cfg.autoStopSilenceMs) {
131
+ autoStopStartRef.current = now;
132
+ setIsAutoStopping(true);
133
+ setAutoStopProgress(1);
134
+ }
135
+ }
136
+ else {
137
+ // Countdown running: drain the ring 1 → 0, then fire.
138
+ const elapsed = now - autoStopStartRef.current;
139
+ const progress = Math.max(0, 1 - elapsed / cfg.autoStopCountdownMs);
140
+ setAutoStopProgress(progress);
141
+ if (elapsed >= cfg.autoStopCountdownMs) {
142
+ autoStopFiredRef.current = true;
143
+ autoStopStartRef.current = null;
144
+ silenceStartRef.current = null;
145
+ setIsAutoStopping(false);
146
+ setAutoStopProgress(1);
147
+ cfg.onAutoStop?.();
148
+ }
149
+ }
150
+ }
151
+ // Hysteresis deadzone (silence < peak < activity): keep timers running.
152
+ }, []);
49
153
  const cleanupAudioGraph = React.useCallback(() => {
50
154
  if (rafRef.current !== null) {
51
155
  cancelAnimationFrame(rafRef.current);
@@ -69,19 +173,24 @@ function useSpeechRecording(options = {}) {
69
173
  analyser.getByteFrequencyData(data);
70
174
  const bucketSize = Math.floor(data.length / bars) || 1;
71
175
  const next = [];
176
+ let peak = 0;
72
177
  for (let i = 0; i < bars; i++) {
73
178
  let sum = 0;
74
179
  for (let j = 0; j < bucketSize; j++) {
75
180
  sum += data[i * bucketSize + j] ?? 0;
76
181
  }
77
182
  // Normalize 0..255 -> 0..1 with a small floor so bars stay visible.
78
- next.push(Math.min(1, sum / bucketSize / 255));
183
+ const level = Math.min(1, sum / bucketSize / 255);
184
+ next.push(level);
185
+ if (level > peak)
186
+ peak = level;
79
187
  }
80
188
  setLevels(next);
189
+ evaluateAutoStop(peak);
81
190
  }
82
191
  setDurationMs(accumulatedRef.current + (Date.now() - startedAtRef.current));
83
192
  rafRef.current = requestAnimationFrame(tick);
84
- }, [bars]);
193
+ }, [bars, evaluateAutoStop]);
85
194
  const start = React.useCallback(async () => {
86
195
  if (!isSupported) {
87
196
  setError('Audio recording is not supported in this browser');
@@ -100,6 +209,7 @@ function useSpeechRecording(options = {}) {
100
209
  mediaRecorderRef.current = recorder;
101
210
  chunksRef.current = [];
102
211
  discardRef.current = false;
212
+ resetAutoStop();
103
213
  recorder.ondataavailable = (e) => {
104
214
  if (e.data && e.data.size > 0)
105
215
  chunksRef.current.push(e.data);
@@ -116,6 +226,7 @@ function useSpeechRecording(options = {}) {
116
226
  setLevels(new Array(bars).fill(0));
117
227
  setDurationMs(0);
118
228
  accumulatedRef.current = 0;
229
+ resetAutoStop();
119
230
  const resolve = stopResolveRef.current;
120
231
  stopResolveRef.current = null;
121
232
  resolve?.(blob);
@@ -146,7 +257,7 @@ function useSpeechRecording(options = {}) {
146
257
  setError(message);
147
258
  setStatus('idle');
148
259
  }
149
- }, [isSupported, mimeType, bars, tick, cleanupAudioGraph]);
260
+ }, [isSupported, mimeType, bars, tick, cleanupAudioGraph, resetAutoStop]);
150
261
  const pause = React.useCallback(() => {
151
262
  const recorder = mediaRecorderRef.current;
152
263
  if (recorder && recorder.state === 'recording') {
@@ -157,18 +268,22 @@ function useSpeechRecording(options = {}) {
157
268
  rafRef.current = null;
158
269
  }
159
270
  setLevels(new Array(bars).fill(0));
271
+ // Drop any in-flight silence/countdown but remember that speech happened.
272
+ resetAutoStop(true);
160
273
  setStatus('paused');
161
274
  }
162
- }, [bars]);
275
+ }, [bars, resetAutoStop]);
163
276
  const resume = React.useCallback(() => {
164
277
  const recorder = mediaRecorderRef.current;
165
278
  if (recorder && recorder.state === 'paused') {
166
279
  recorder.resume();
167
280
  startedAtRef.current = Date.now();
281
+ // Fresh silence timing on resume so it doesn't fire immediately.
282
+ resetAutoStop(true);
168
283
  rafRef.current = requestAnimationFrame(tick);
169
284
  setStatus('recording');
170
285
  }
171
- }, [tick]);
286
+ }, [tick, resetAutoStop]);
172
287
  const stop = React.useCallback(() => {
173
288
  const recorder = mediaRecorderRef.current;
174
289
  if (!recorder)
@@ -186,11 +301,12 @@ function useSpeechRecording(options = {}) {
186
301
  setStatus('idle');
187
302
  setLevels(new Array(bars).fill(0));
188
303
  setDurationMs(0);
304
+ resetAutoStop();
189
305
  return;
190
306
  }
191
307
  discardRef.current = true;
192
308
  recorder.stop();
193
- }, [bars, cleanupAudioGraph]);
309
+ }, [bars, cleanupAudioGraph, resetAutoStop]);
194
310
  // Teardown on unmount.
195
311
  React.useEffect(() => {
196
312
  return () => {
@@ -215,6 +331,8 @@ function useSpeechRecording(options = {}) {
215
331
  levels,
216
332
  durationMs,
217
333
  error,
334
+ isAutoStopping,
335
+ autoStopProgress,
218
336
  start,
219
337
  pause,
220
338
  resume,
@@ -1 +1 @@
1
- {"version":3,"file":"useSpeechRecording.js","sources":["../../../../src/hooks/useSpeechRecording.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\n/**\n * Recording lifecycle state.\n * - `idle`: not recording\n * - `recording`: actively capturing audio\n * - `paused`: capture paused, can be resumed\n */\nexport type SpeechRecordingStatus = 'idle' | 'recording' | 'paused';\n\nexport interface UseSpeechRecordingOptions {\n /** Number of equalizer bars to expose in `levels`. @default 5 */\n bars?: number;\n /** Preferred MediaRecorder mime type. Falls back to a supported one. */\n mimeType?: string;\n}\n\nexport interface UseSpeechRecordingResult {\n status: SpeechRecordingStatus;\n isRecording: boolean;\n isPaused: boolean;\n /** Whether the browser supports audio recording. */\n isSupported: boolean;\n /** Normalized amplitude per bar (0..1), updated in real time for the equalizer. */\n levels: number[];\n /** Elapsed recording time in milliseconds (excludes paused time). */\n durationMs: number;\n /** Last error message, if any (e.g. permission denied). */\n error: string | null;\n /** Request mic access and start recording. */\n start: () => Promise<void>;\n /** Pause an active recording. */\n pause: () => void;\n /** Resume a paused recording. */\n resume: () => void;\n /** Stop and return the recorded audio as a Blob (null if nothing captured). */\n stop: () => Promise<Blob | null>;\n /** Stop and discard the recording without producing a Blob. */\n cancel: () => void;\n}\n\nconst PREFERRED_MIME_TYPES = [\n 'audio/webm;codecs=opus',\n 'audio/webm',\n 'audio/ogg;codecs=opus',\n 'audio/mp4',\n];\n\nfunction pickMimeType(preferred?: string): string | undefined {\n if (typeof MediaRecorder === 'undefined') return undefined;\n const candidates = preferred\n ? [preferred, ...PREFERRED_MIME_TYPES]\n : PREFERRED_MIME_TYPES;\n for (const type of candidates) {\n if (MediaRecorder.isTypeSupported(type)) return type;\n }\n return undefined;\n}\n\n/**\n * Encapsulates microphone capture via MediaRecorder plus a Web Audio analyser\n * that exposes live amplitude levels for an equalizer-style animation.\n *\n * The hook owns all teardown: stopping tracks, closing the AudioContext and\n * cancelling the animation frame on stop/cancel/unmount.\n */\nexport function useSpeechRecording(\n options: UseSpeechRecordingOptions = {},\n): UseSpeechRecordingResult {\n const { bars = 5, mimeType } = options;\n\n const isSupported =\n typeof navigator !== 'undefined' &&\n !!navigator.mediaDevices?.getUserMedia &&\n typeof MediaRecorder !== 'undefined';\n\n const [status, setStatus] = useState<SpeechRecordingStatus>('idle');\n const [levels, setLevels] = useState<number[]>(() => new Array(bars).fill(0));\n const [durationMs, setDurationMs] = useState(0);\n const [error, setError] = useState<string | null>(null);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n const audioContextRef = useRef<AudioContext | null>(null);\n const analyserRef = useRef<AnalyserNode | null>(null);\n const rafRef = useRef<number | null>(null);\n const startedAtRef = useRef<number>(0);\n const accumulatedRef = useRef<number>(0);\n const stopResolveRef = useRef<((blob: Blob | null) => void) | null>(null);\n const discardRef = useRef<boolean>(false);\n\n const cleanupAudioGraph = useCallback(() => {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => undefined);\n audioContextRef.current = null;\n }\n analyserRef.current = null;\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((t) => t.stop());\n streamRef.current = null;\n }\n }, []);\n\n // Drives both the equalizer levels and the duration counter.\n const tick = useCallback(() => {\n const analyser = analyserRef.current;\n if (analyser) {\n const data = new Uint8Array(analyser.frequencyBinCount);\n analyser.getByteFrequencyData(data);\n const bucketSize = Math.floor(data.length / bars) || 1;\n const next: number[] = [];\n for (let i = 0; i < bars; i++) {\n let sum = 0;\n for (let j = 0; j < bucketSize; j++) {\n sum += data[i * bucketSize + j] ?? 0;\n }\n // Normalize 0..255 -> 0..1 with a small floor so bars stay visible.\n next.push(Math.min(1, sum / bucketSize / 255));\n }\n setLevels(next);\n }\n setDurationMs(accumulatedRef.current + (Date.now() - startedAtRef.current));\n rafRef.current = requestAnimationFrame(tick);\n }, [bars]);\n\n const start = useCallback(async () => {\n if (!isSupported) {\n setError('Audio recording is not supported in this browser');\n return;\n }\n if (mediaRecorderRef.current) return;\n\n setError(null);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n streamRef.current = stream;\n\n const selectedType = pickMimeType(mimeType);\n const recorder = selectedType\n ? new MediaRecorder(stream, { mimeType: selectedType })\n : new MediaRecorder(stream);\n mediaRecorderRef.current = recorder;\n chunksRef.current = [];\n discardRef.current = false;\n\n recorder.ondataavailable = (e: BlobEvent) => {\n if (e.data && e.data.size > 0) chunksRef.current.push(e.data);\n };\n recorder.onstop = () => {\n const type = recorder.mimeType || selectedType || 'audio/webm';\n const blob = discardRef.current\n ? null\n : new Blob(chunksRef.current, { type });\n chunksRef.current = [];\n cleanupAudioGraph();\n mediaRecorderRef.current = null;\n setStatus('idle');\n setLevels(new Array(bars).fill(0));\n setDurationMs(0);\n accumulatedRef.current = 0;\n const resolve = stopResolveRef.current;\n stopResolveRef.current = null;\n resolve?.(blob);\n };\n\n // Web Audio analyser for the equalizer animation.\n const AudioCtx =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext })\n .webkitAudioContext;\n const audioContext = new AudioCtx();\n const source = audioContext.createMediaStreamSource(stream);\n const analyser = audioContext.createAnalyser();\n analyser.fftSize = 64;\n source.connect(analyser);\n audioContextRef.current = audioContext;\n analyserRef.current = analyser;\n\n accumulatedRef.current = 0;\n startedAtRef.current = Date.now();\n recorder.start(100);\n setStatus('recording');\n rafRef.current = requestAnimationFrame(tick);\n } catch (e) {\n cleanupAudioGraph();\n mediaRecorderRef.current = null;\n const message =\n (e as Error)?.name === 'NotAllowedError'\n ? 'Microphone permission denied'\n : `Could not start recording: ${(e as Error)?.message || 'unknown error'}`;\n setError(message);\n setStatus('idle');\n }\n }, [isSupported, mimeType, bars, tick, cleanupAudioGraph]);\n\n const pause = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state === 'recording') {\n recorder.pause();\n accumulatedRef.current += Date.now() - startedAtRef.current;\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n setLevels(new Array(bars).fill(0));\n setStatus('paused');\n }\n }, [bars]);\n\n const resume = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state === 'paused') {\n recorder.resume();\n startedAtRef.current = Date.now();\n rafRef.current = requestAnimationFrame(tick);\n setStatus('recording');\n }\n }, [tick]);\n\n const stop = useCallback((): Promise<Blob | null> => {\n const recorder = mediaRecorderRef.current;\n if (!recorder) return Promise.resolve(null);\n discardRef.current = false;\n return new Promise<Blob | null>((resolve) => {\n stopResolveRef.current = resolve;\n recorder.stop();\n });\n }, []);\n\n const cancel = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (!recorder) {\n cleanupAudioGraph();\n setStatus('idle');\n setLevels(new Array(bars).fill(0));\n setDurationMs(0);\n return;\n }\n discardRef.current = true;\n recorder.stop();\n }, [bars, cleanupAudioGraph]);\n\n // Teardown on unmount.\n useEffect(() => {\n return () => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state !== 'inactive') {\n discardRef.current = true;\n try {\n recorder.stop();\n } catch {\n // ignore\n }\n }\n cleanupAudioGraph();\n };\n }, [cleanupAudioGraph]);\n\n return {\n status,\n isRecording: status === 'recording',\n isPaused: status === 'paused',\n isSupported,\n levels,\n durationMs,\n error,\n start,\n pause,\n resume,\n stop,\n cancel,\n };\n}\n"],"names":["useState","useRef","useCallback","useEffect"],"mappings":"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"}
1
+ {"version":3,"file":"useSpeechRecording.js","sources":["../../../../src/hooks/useSpeechRecording.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\n/**\n * Recording lifecycle state.\n * - `idle`: not recording\n * - `recording`: actively capturing audio\n * - `paused`: capture paused, can be resumed\n */\nexport type SpeechRecordingStatus = 'idle' | 'recording' | 'paused';\n\nexport interface UseSpeechRecordingOptions {\n /** Number of equalizer bars to expose in `levels`. @default 5 */\n bars?: number;\n /** Preferred MediaRecorder mime type. Falls back to a supported one. */\n mimeType?: string;\n /**\n * Auto-stop the recording after a short silence, but only once speech has\n * actually been detected. When it triggers, the countdown runs and then\n * `onAutoStop` is fired. Disable to require a manual confirm. @default true\n */\n autoStop?: boolean;\n /**\n * Continuous silence (ms) that must elapse — after speech was detected —\n * before the auto-stop countdown begins. @default 1000\n */\n autoStopSilenceMs?: number;\n /** Duration (ms) of the auto-stop countdown shown before firing. @default 1000 */\n autoStopCountdownMs?: number;\n /**\n * Silence is **adaptive**: the threshold is this fraction of the loudest\n * speech observed in the recording (e.g. 0.1 = 10% of peak voice). This makes\n * it robust to ambient noise — a quiet room and a loud one calibrate\n * differently. @default 0.1\n */\n autoStopSilenceRatio?: number;\n /**\n * Absolute floor (0..1) for the adaptive silence threshold, so it never drops\n * so low that background hiss reads as \"sound\". @default 0.02\n */\n autoStopSilenceLevel?: number;\n /**\n * Absolute floor (0..1) a peak must clear to first count as speech (arms the\n * detector / calibrates the reference loudness). @default 0.12\n */\n autoStopSpeechLevel?: number;\n /**\n * Fired when the silence countdown completes. The consumer decides what\n * \"stop\" means (e.g. confirm + transcribe). Read fresh on every frame, so it\n * does not need to be memoized.\n */\n onAutoStop?: () => void;\n}\n\nexport interface UseSpeechRecordingResult {\n status: SpeechRecordingStatus;\n isRecording: boolean;\n isPaused: boolean;\n /** Whether the browser supports audio recording. */\n isSupported: boolean;\n /** Normalized amplitude per bar (0..1), updated in real time for the equalizer. */\n levels: number[];\n /** Elapsed recording time in milliseconds (excludes paused time). */\n durationMs: number;\n /** Last error message, if any (e.g. permission denied). */\n error: string | null;\n /** True while the silence-triggered auto-stop countdown is running. */\n isAutoStopping: boolean;\n /** Auto-stop countdown progress, 1 (full) → 0 (empty), for an inverted ring. */\n autoStopProgress: number;\n /** Request mic access and start recording. */\n start: () => Promise<void>;\n /** Pause an active recording. */\n pause: () => void;\n /** Resume a paused recording. */\n resume: () => void;\n /** Stop and return the recorded audio as a Blob (null if nothing captured). */\n stop: () => Promise<Blob | null>;\n /** Stop and discard the recording without producing a Blob. */\n cancel: () => void;\n}\n\nconst PREFERRED_MIME_TYPES = [\n 'audio/webm;codecs=opus',\n 'audio/webm',\n 'audio/ogg;codecs=opus',\n 'audio/mp4',\n];\n\nfunction pickMimeType(preferred?: string): string | undefined {\n if (typeof MediaRecorder === 'undefined') return undefined;\n const candidates = preferred\n ? [preferred, ...PREFERRED_MIME_TYPES]\n : PREFERRED_MIME_TYPES;\n for (const type of candidates) {\n if (MediaRecorder.isTypeSupported(type)) return type;\n }\n return undefined;\n}\n\n/**\n * Encapsulates microphone capture via MediaRecorder plus a Web Audio analyser\n * that exposes live amplitude levels for an equalizer-style animation.\n *\n * The hook owns all teardown: stopping tracks, closing the AudioContext and\n * cancelling the animation frame on stop/cancel/unmount.\n */\nexport function useSpeechRecording(\n options: UseSpeechRecordingOptions = {},\n): UseSpeechRecordingResult {\n const {\n bars = 5,\n mimeType,\n autoStop = true,\n autoStopSilenceMs = 1000,\n autoStopCountdownMs = 1000,\n autoStopSilenceRatio = 0.1,\n autoStopSilenceLevel = 0.02,\n autoStopSpeechLevel = 0.12,\n onAutoStop,\n } = options;\n\n const isSupported =\n typeof navigator !== 'undefined' &&\n !!navigator.mediaDevices?.getUserMedia &&\n typeof MediaRecorder !== 'undefined';\n\n const [status, setStatus] = useState<SpeechRecordingStatus>('idle');\n const [levels, setLevels] = useState<number[]>(() => new Array(bars).fill(0));\n const [durationMs, setDurationMs] = useState(0);\n const [error, setError] = useState<string | null>(null);\n const [isAutoStopping, setIsAutoStopping] = useState(false);\n const [autoStopProgress, setAutoStopProgress] = useState(1);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const chunksRef = useRef<Blob[]>([]);\n const audioContextRef = useRef<AudioContext | null>(null);\n const analyserRef = useRef<AnalyserNode | null>(null);\n const rafRef = useRef<number | null>(null);\n const startedAtRef = useRef<number>(0);\n const accumulatedRef = useRef<number>(0);\n const stopResolveRef = useRef<((blob: Blob | null) => void) | null>(null);\n const discardRef = useRef<boolean>(false);\n\n // --- Auto-stop (silence detection) state, all kept in refs so the rAF loop\n // reads it without forcing `tick` to re-subscribe. ---\n const hasSpeechRef = useRef(false); // user has spoken at least once\n const loudestRef = useRef(0); // loudest peak seen (reference for adaptive silence)\n const silenceStartRef = useRef<number | null>(null); // when current silence began\n const autoStopStartRef = useRef<number | null>(null); // when the countdown started\n const autoStopFiredRef = useRef(false); // guard against re-firing before stop\n // Latest-config ref so the loop always sees fresh thresholds and callback.\n const autoStopCfgRef = useRef({\n autoStop,\n autoStopSilenceMs,\n autoStopCountdownMs,\n autoStopSilenceRatio,\n autoStopSilenceLevel,\n autoStopSpeechLevel,\n onAutoStop,\n });\n autoStopCfgRef.current = {\n autoStop,\n autoStopSilenceMs,\n autoStopCountdownMs,\n autoStopSilenceRatio,\n autoStopSilenceLevel,\n autoStopSpeechLevel,\n onAutoStop,\n };\n\n // Reset all auto-stop tracking. `keepSpeech` preserves the \"user has spoken\"\n // flag across a pause/resume so it doesn't re-arm from scratch.\n const resetAutoStop = useCallback((keepSpeech = false) => {\n if (!keepSpeech) {\n hasSpeechRef.current = false;\n loudestRef.current = 0;\n }\n silenceStartRef.current = null;\n autoStopStartRef.current = null;\n autoStopFiredRef.current = false;\n setIsAutoStopping(false);\n setAutoStopProgress(1);\n }, []);\n\n // Evaluate the current peak amplitude against the silence/speech thresholds\n // and drive the auto-stop countdown. Called once per animation frame.\n const evaluateAutoStop = useCallback((peak: number) => {\n const cfg = autoStopCfgRef.current;\n if (!cfg.autoStop || autoStopFiredRef.current) return;\n const now = Date.now();\n\n // 1) Arm only once a real voice peak (absolute floor) has been heard. This\n // also seeds the reference loudness so ambient noise alone can't arm it.\n if (!hasSpeechRef.current) {\n if (peak >= cfg.autoStopSpeechLevel) {\n hasSpeechRef.current = true;\n loudestRef.current = peak;\n }\n return;\n }\n\n // 2) Track the loudest voice so the silence threshold scales with how loud\n // the user actually speaks (robust to ambient noise).\n if (peak > loudestRef.current) loudestRef.current = peak;\n\n // 3) Adaptive thresholds: silence = ratio of the loudest voice (with an\n // absolute floor); activity sits above it for hysteresis, so background\n // noise between the two doesn't keep cancelling the countdown.\n const silenceThreshold = Math.max(\n cfg.autoStopSilenceLevel,\n cfg.autoStopSilenceRatio * loudestRef.current,\n );\n const activityThreshold = silenceThreshold * 1.8;\n\n if (peak >= activityThreshold) {\n // Talking again: reset silence and cancel any pending countdown.\n silenceStartRef.current = null;\n if (autoStopStartRef.current !== null) {\n autoStopStartRef.current = null;\n setIsAutoStopping(false);\n setAutoStopProgress(1);\n }\n return;\n }\n\n if (peak <= silenceThreshold) {\n if (silenceStartRef.current === null) silenceStartRef.current = now;\n\n if (autoStopStartRef.current === null) {\n // Waiting out the silence window before the countdown begins.\n if (now - silenceStartRef.current >= cfg.autoStopSilenceMs) {\n autoStopStartRef.current = now;\n setIsAutoStopping(true);\n setAutoStopProgress(1);\n }\n } else {\n // Countdown running: drain the ring 1 → 0, then fire.\n const elapsed = now - autoStopStartRef.current;\n const progress = Math.max(0, 1 - elapsed / cfg.autoStopCountdownMs);\n setAutoStopProgress(progress);\n if (elapsed >= cfg.autoStopCountdownMs) {\n autoStopFiredRef.current = true;\n autoStopStartRef.current = null;\n silenceStartRef.current = null;\n setIsAutoStopping(false);\n setAutoStopProgress(1);\n cfg.onAutoStop?.();\n }\n }\n }\n // Hysteresis deadzone (silence < peak < activity): keep timers running.\n }, []);\n\n const cleanupAudioGraph = useCallback(() => {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n if (audioContextRef.current) {\n audioContextRef.current.close().catch(() => undefined);\n audioContextRef.current = null;\n }\n analyserRef.current = null;\n if (streamRef.current) {\n streamRef.current.getTracks().forEach((t) => t.stop());\n streamRef.current = null;\n }\n }, []);\n\n // Drives both the equalizer levels and the duration counter.\n const tick = useCallback(() => {\n const analyser = analyserRef.current;\n if (analyser) {\n const data = new Uint8Array(analyser.frequencyBinCount);\n analyser.getByteFrequencyData(data);\n const bucketSize = Math.floor(data.length / bars) || 1;\n const next: number[] = [];\n let peak = 0;\n for (let i = 0; i < bars; i++) {\n let sum = 0;\n for (let j = 0; j < bucketSize; j++) {\n sum += data[i * bucketSize + j] ?? 0;\n }\n // Normalize 0..255 -> 0..1 with a small floor so bars stay visible.\n const level = Math.min(1, sum / bucketSize / 255);\n next.push(level);\n if (level > peak) peak = level;\n }\n setLevels(next);\n evaluateAutoStop(peak);\n }\n setDurationMs(accumulatedRef.current + (Date.now() - startedAtRef.current));\n rafRef.current = requestAnimationFrame(tick);\n }, [bars, evaluateAutoStop]);\n\n const start = useCallback(async () => {\n if (!isSupported) {\n setError('Audio recording is not supported in this browser');\n return;\n }\n if (mediaRecorderRef.current) return;\n\n setError(null);\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n streamRef.current = stream;\n\n const selectedType = pickMimeType(mimeType);\n const recorder = selectedType\n ? new MediaRecorder(stream, { mimeType: selectedType })\n : new MediaRecorder(stream);\n mediaRecorderRef.current = recorder;\n chunksRef.current = [];\n discardRef.current = false;\n resetAutoStop();\n\n recorder.ondataavailable = (e: BlobEvent) => {\n if (e.data && e.data.size > 0) chunksRef.current.push(e.data);\n };\n recorder.onstop = () => {\n const type = recorder.mimeType || selectedType || 'audio/webm';\n const blob = discardRef.current\n ? null\n : new Blob(chunksRef.current, { type });\n chunksRef.current = [];\n cleanupAudioGraph();\n mediaRecorderRef.current = null;\n setStatus('idle');\n setLevels(new Array(bars).fill(0));\n setDurationMs(0);\n accumulatedRef.current = 0;\n resetAutoStop();\n const resolve = stopResolveRef.current;\n stopResolveRef.current = null;\n resolve?.(blob);\n };\n\n // Web Audio analyser for the equalizer animation.\n const AudioCtx =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext })\n .webkitAudioContext;\n const audioContext = new AudioCtx();\n const source = audioContext.createMediaStreamSource(stream);\n const analyser = audioContext.createAnalyser();\n analyser.fftSize = 64;\n source.connect(analyser);\n audioContextRef.current = audioContext;\n analyserRef.current = analyser;\n\n accumulatedRef.current = 0;\n startedAtRef.current = Date.now();\n recorder.start(100);\n setStatus('recording');\n rafRef.current = requestAnimationFrame(tick);\n } catch (e) {\n cleanupAudioGraph();\n mediaRecorderRef.current = null;\n const message =\n (e as Error)?.name === 'NotAllowedError'\n ? 'Microphone permission denied'\n : `Could not start recording: ${(e as Error)?.message || 'unknown error'}`;\n setError(message);\n setStatus('idle');\n }\n }, [isSupported, mimeType, bars, tick, cleanupAudioGraph, resetAutoStop]);\n\n const pause = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state === 'recording') {\n recorder.pause();\n accumulatedRef.current += Date.now() - startedAtRef.current;\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n setLevels(new Array(bars).fill(0));\n // Drop any in-flight silence/countdown but remember that speech happened.\n resetAutoStop(true);\n setStatus('paused');\n }\n }, [bars, resetAutoStop]);\n\n const resume = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state === 'paused') {\n recorder.resume();\n startedAtRef.current = Date.now();\n // Fresh silence timing on resume so it doesn't fire immediately.\n resetAutoStop(true);\n rafRef.current = requestAnimationFrame(tick);\n setStatus('recording');\n }\n }, [tick, resetAutoStop]);\n\n const stop = useCallback((): Promise<Blob | null> => {\n const recorder = mediaRecorderRef.current;\n if (!recorder) return Promise.resolve(null);\n discardRef.current = false;\n return new Promise<Blob | null>((resolve) => {\n stopResolveRef.current = resolve;\n recorder.stop();\n });\n }, []);\n\n const cancel = useCallback(() => {\n const recorder = mediaRecorderRef.current;\n if (!recorder) {\n cleanupAudioGraph();\n setStatus('idle');\n setLevels(new Array(bars).fill(0));\n setDurationMs(0);\n resetAutoStop();\n return;\n }\n discardRef.current = true;\n recorder.stop();\n }, [bars, cleanupAudioGraph, resetAutoStop]);\n\n // Teardown on unmount.\n useEffect(() => {\n return () => {\n const recorder = mediaRecorderRef.current;\n if (recorder && recorder.state !== 'inactive') {\n discardRef.current = true;\n try {\n recorder.stop();\n } catch {\n // ignore\n }\n }\n cleanupAudioGraph();\n };\n }, [cleanupAudioGraph]);\n\n return {\n status,\n isRecording: status === 'recording',\n isPaused: status === 'paused',\n isSupported,\n levels,\n durationMs,\n error,\n isAutoStopping,\n autoStopProgress,\n start,\n pause,\n resume,\n stop,\n cancel,\n };\n}\n"],"names":["useState","useRef","useCallback","useEffect"],"mappings":"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"}
@@ -1 +1 @@
1
- .devic-state-tag{align-items:center;border:1px solid;border-radius:4px;cursor:default;display:inline-flex;font-family:var(--devic-font-family,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);font-size:12px;font-weight:500;gap:6px;line-height:20px;padding:2px 8px;position:relative;white-space:nowrap}.devic-state-tag[data-interactive=true]{cursor:pointer}.devic-state-tag[data-interactive=true]:hover{opacity:.85}.devic-state-tag[data-color=gold]{background:rgba(250,173,20,.15);border-color:rgba(250,173,20,.35);color:#faad14}.devic-state-tag[data-color=processing]{background:rgba(22,119,255,.15);border-color:rgba(22,119,255,.35);color:#4096ff}.devic-state-tag[data-color=success]{background:rgba(82,196,26,.15);border-color:rgba(82,196,26,.35);color:#52c41a}.devic-state-tag[data-color=error]{background:rgba(255,77,79,.15);border-color:rgba(255,77,79,.35);color:#ff4d4f}.devic-state-tag[data-color=default]{background:hsla(0,0%,60%,.15);border-color:hsla(0,0%,60%,.35);color:#999}.devic-state-tag[data-color=purple]{background:rgba(114,46,209,.15);border-color:rgba(114,46,209,.35);color:#b37feb}.devic-state-tag[data-color=blue]{background:rgba(22,119,255,.15);border-color:rgba(22,119,255,.35);color:#4096ff}.devic-state-tag-icon{align-items:center;display:inline-flex;flex-shrink:0}.devic-state-tag-caret{align-items:center;display:inline-flex;margin-left:2px;transition:transform .2s ease}.devic-state-tag[data-dropdown-open=true] .devic-state-tag-caret{transform:rotate(180deg)}.devic-state-spinner{animation:devic-state-spin 1s linear infinite}@keyframes devic-state-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.devic-state-tooltip{background:rgba(0,0,0,.85);border-radius:6px;bottom:calc(100% + 8px);color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:400;line-height:1.4;max-width:280px;padding:6px 10px;pointer-events:none;white-space:normal;z-index:1060}.devic-state-tooltip,.devic-state-tooltip:after{left:50%;position:absolute;transform:translateX(-50%)}.devic-state-tooltip:after{border:5px solid transparent;border-top-color:rgba(0,0,0,.85);content:"";top:100%}.devic-state-dropdown{animation:devic-dropdownSlide .15s ease-out;background:#fff;border:1px solid #e8e8e8;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08),0 3px 6px rgba(0,0,0,.06);min-width:180px;padding:4px 0;position:absolute;right:0;top:calc(100% + 4px);z-index:1050}@keyframes devic-dropdownSlide{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.devic-state-dropdown-item{align-items:center;background:none;border:none;color:#333;cursor:pointer;display:flex;font-family:inherit;font-size:13px;gap:8px;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-state-dropdown-item:hover{background:#f5f5f5}.devic-state-dropdown-item-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center;width:18px}.devic-state-tooltip-portal{background:rgba(0,0,0,.85);border-radius:6px;color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:400;line-height:1.4;max-width:280px;padding:6px 10px;pointer-events:none;white-space:normal;z-index:99999}.devic-state-dropdown-portal{animation:devic-dropdownSlide .15s ease-out;background:#fff;border:1px solid #e8e8e8;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08),0 3px 6px rgba(0,0,0,.06);min-width:180px;padding:4px 0;z-index:99999}.devic-state-modal-overlay{align-items:center;animation:devic-fadeIn .2s ease;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;position:fixed;z-index:1050}@keyframes devic-fadeIn{0%{opacity:0}to{opacity:1}}.devic-state-modal{animation:devic-modalSlide .2s ease-out;background:#fff;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08);display:flex;flex-direction:column;max-height:80vh;max-width:520px;width:90%}@keyframes devic-modalSlide{0%{opacity:0;transform:translateY(-16px)}to{opacity:1;transform:translateY(0)}}.devic-state-modal-header{align-items:center;border-bottom:1px solid #f0f0f0;display:flex;justify-content:space-between;padding:16px 20px}.devic-state-modal-title{align-items:center;display:flex;font-size:16px;font-weight:600;gap:8px;margin:0}.devic-state-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:#999;cursor:pointer;display:flex;padding:4px}.devic-state-modal-close:hover{background:#f5f5f5;color:#333}.devic-state-modal-body{flex:1;overflow-y:auto;padding:20px}.devic-state-modal-footer{border-top:1px solid #f0f0f0;display:flex;gap:8px;justify-content:flex-end;padding:12px 20px}.devic-state-btn{align-items:center;background:#fff;border:1px solid #d9d9d9;border-radius:6px;color:#333;cursor:pointer;display:inline-flex;font-family:inherit;font-size:14px;font-weight:500;gap:6px;justify-content:center;padding:6px 16px;transition:all .2s}.devic-state-btn:hover{border-color:#1677ff;color:#1677ff}.devic-state-btn-primary{background:#1677ff;border-color:#1677ff;color:#fff}.devic-state-btn-primary:hover{background:#4096ff;border-color:#4096ff;color:#fff}.devic-state-btn-danger{background:#ff4d4f;border-color:#ff4d4f;color:#fff}.devic-state-btn-danger:hover{background:#ff7875;border-color:#ff7875;color:#fff}.devic-state-btn-success{background:#52c41a;border-color:#52c41a;color:#fff}.devic-state-btn-success:hover{background:#73d13d;border-color:#73d13d;color:#fff}.devic-state-btn:disabled{cursor:not-allowed;opacity:.5}.devic-explain-content{border:1px solid #e8e8e8;border-radius:8px;font-family:SFMono-Regular,Consolas,monospace;font-size:13px;line-height:1.6;max-height:300px;min-height:150px;overflow-y:auto;padding:12px;white-space:pre-wrap}.devic-typing-cursor{animation:devic-blink 1s step-end infinite}@keyframes devic-blink{0%,to{opacity:1}50%{opacity:0}}.devic-approval-layout{display:flex;gap:16px}.devic-approval-request{background:#fafafa;border:1px solid #e8e8e8;border-radius:8px;flex:1;font-size:13px;line-height:1.6;max-height:250px;overflow-y:auto;padding:12px}.devic-approval-actions{display:flex;flex:1;flex-direction:column;gap:12px}.devic-approval-textarea{border:1px solid #d9d9d9;border-radius:6px;box-sizing:border-box;font-family:inherit;font-size:13px;min-height:80px;outline:none;padding:8px 12px;resize:vertical;width:100%}.devic-approval-textarea:focus{border-color:#1677ff}.devic-approval-buttons{display:flex;flex-direction:column;gap:8px}.devic-completion-select{background:#fff;border:1px solid #d9d9d9;border-radius:6px;cursor:pointer;font-family:inherit;font-size:14px;outline:none;padding:8px 12px;width:100%}.devic-completion-select:focus{border-color:#1677ff}.devic-state-loading{align-items:center;display:flex;justify-content:center;padding:24px}.devic-state-loading-spinner{animation:devic-state-spin .8s linear infinite;border:2px solid #f0f0f0;border-radius:50%;border-top-color:#1677ff;height:24px;width:24px}.devic-state-warning{align-items:flex-start;color:#cf1322;display:flex;font-size:13px;font-weight:500;gap:6px;margin-top:8px}.devic-message-actions{align-items:center;display:flex;gap:4px;opacity:0;transition:opacity .15s ease}.devic-message-actions:focus-within,.devic-message:hover .devic-message-actions{opacity:1}.devic-message-actions:has(.devic-action-btn--active){opacity:1}.devic-action-btn{align-items:center;background:transparent;border:none;border-radius:var(--devic-radius-sm,6px);color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-action-btn:hover:not(:disabled){background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-action-btn:disabled{cursor:not-allowed;opacity:.5}.devic-action-btn--active{color:var(--devic-primary,#3b82f6)}.devic-action-btn--active.devic-action-btn--positive{color:#22c55e}.devic-action-btn--active.devic-action-btn--negative{color:#ef4444}.devic-feedback-overlay{align-items:center;animation:devic-feedback-fade-in .15s ease;background:rgba(0,0,0,.4);bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:10001}@keyframes devic-feedback-fade-in{0%{opacity:0}to{opacity:1}}.devic-feedback-modal{animation:devic-feedback-slide-up .2s ease;background:var(--devic-bg,#fff);border-radius:var(--devic-radius,12px);box-shadow:0 20px 60px rgba(0,0,0,.2);margin:16px;max-width:400px;width:100%}@keyframes devic-feedback-slide-up{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.devic-feedback-modal-header{align-items:center;border-bottom:1px solid var(--devic-border,#e2e8f0);display:flex;gap:10px;padding:16px 16px 12px}.devic-feedback-modal-icon{align-items:center;background:var(--devic-bg-secondary,#f8fafc);border-radius:8px;color:var(--devic-text,#1e293b);display:flex;height:32px;justify-content:center;width:32px}.devic-feedback-modal-title{color:var(--devic-text,#1e293b);flex:1;font-size:15px;font-weight:600}.devic-feedback-modal-close{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-feedback-modal-close:hover{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-textarea{background:transparent;border:none;border-bottom:1px solid var(--devic-border,#e2e8f0);box-sizing:border-box;color:var(--devic-text,#1e293b);display:block;font-family:inherit;font-size:14px;line-height:1.5;padding:12px 16px;resize:none;width:100%}.devic-feedback-textarea:focus{outline:none}.devic-feedback-textarea::placeholder{color:var(--devic-text-muted,#94a3b8)}.devic-feedback-modal-actions{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px}.devic-feedback-btn{border:none;border-radius:var(--devic-radius-sm,6px);cursor:pointer;font-family:inherit;font-size:14px;font-weight:500;padding:8px 16px;transition:all .15s ease}.devic-feedback-btn:disabled{cursor:not-allowed;opacity:.6}.devic-feedback-btn--secondary{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-btn--secondary:hover:not(:disabled){background:var(--devic-border,#e2e8f0)}.devic-feedback-btn--primary{background:var(--devic-primary,#3b82f6);color:#fff}.devic-feedback-btn--primary:hover:not(:disabled){background:var(--devic-primary-hover,#2563eb)}.devic-cmd-result-actions{border-top:1px solid var(--devic-cmd-border,var(--devic-border,#e5e7eb));margin-top:8px;padding-top:8px}.devic-cmd-result-actions .devic-message-actions{opacity:1;padding-left:10px}.devic-cmd-result-actions .devic-action-btn{opacity:.7}.devic-cmd-result-actions .devic-action-btn--active,.devic-cmd-result-actions .devic-action-btn:hover{opacity:1}.devic-chat-drawer{--devic-primary:#1890ff;--devic-primary-hover:#40a9ff;--devic-primary-light:#e6f7ff;--devic-bg:#fff;--devic-bg-secondary:#f5f5f5;--devic-text:#333;--devic-text-secondary:#666;--devic-text-muted:#999;--devic-border:#e8e8e8;--devic-shadow:0 4px 12px rgba(0,0,0,.15);--devic-radius:8px;--devic-radius-sm:4px;--devic-radius-lg:16px;--devic-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--devic-transition:0.3s ease;background:var(--devic-bg);bottom:0;box-shadow:var(--devic-shadow);color:var(--devic-text);display:flex;flex-direction:column;font-family:var(--devic-font-family);font-size:14px;line-height:1.5;position:fixed;top:0;transition:transform var(--devic-transition)}.devic-chat-drawer[data-position=right]{right:0;transform:translateX(100%)}.devic-chat-drawer[data-position=left]{left:0;transform:translateX(-100%)}.devic-chat-drawer[data-open=true]{transform:translateX(0)}.devic-drawer-overlay{background:rgba(0,0,0,.3);inset:0;opacity:0;position:fixed;transition:opacity var(--devic-transition),visibility var(--devic-transition);visibility:hidden}.devic-drawer-overlay[data-open=true]{opacity:1;visibility:visible}.devic-drawer-header{align-items:center;border-bottom:1px solid var(--devic-border);display:flex;flex-shrink:0;justify-content:space-between;padding:16px}.devic-drawer-avatar{border-radius:50%;flex-shrink:0;height:28px;object-fit:cover;width:28px}.devic-drawer-title{font-size:16px;font-weight:600;margin:0}.devic-drawer-close{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-drawer-close:hover{background:var(--devic-bg-secondary);color:var(--devic-text)}.devic-messages-container{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.devic-welcome{color:var(--devic-text-secondary);padding:24px 16px;text-align:center}.devic-welcome-text{font-size:16px;margin-bottom:16px}.devic-suggested-messages{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}.devic-suggested-btn{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-lg);color:var(--devic-text);cursor:pointer;font-size:13px;padding:8px 16px;transition:border-color var(--devic-transition),background var(--devic-transition)}.devic-suggested-btn:hover{background:var(--devic-primary-light);border-color:var(--devic-primary)}.devic-message{display:flex;flex-direction:column;max-width:85%}.devic-message[data-role=user]{align-self:flex-end}.devic-message[data-role=assistant],.devic-message[data-role=tool]{align-self:flex-start}.devic-message-bubble{word-wrap:break-word;border-radius:var(--devic-radius);padding:10px 14px}.devic-message[data-role=user] .devic-message-bubble{background:var(--devic-user-bubble,var(--devic-primary));border-bottom-right-radius:var(--devic-radius-sm);color:var(--devic-user-bubble-text,#fff)}.devic-message[data-role=assistant] .devic-message-bubble{background:var(--devic-assistant-bubble,var(--devic-bg-secondary));border-bottom-left-radius:var(--devic-radius-sm);color:var(--devic-assistant-bubble-text,var(--devic-text))}.devic-message[data-role=tool] .devic-message-bubble{background:var(--devic-primary-light);border:1px solid var(--devic-primary);color:var(--devic-text);font-size:12px}.devic-message-footer{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-top:4px}.devic-message-time{color:var(--devic-text-muted);font-size:11px}.devic-message[data-role=user] .devic-message-footer{justify-content:flex-end}.devic-message[data-role=user] .devic-message-time{text-align:right}.devic-message-files{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.devic-message-file{align-items:center;background:hsla(0,0%,100%,.2);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:6px 10px}.devic-loading{align-self:flex-start;display:flex;gap:4px;padding:10px 14px}.devic-loading-dot{animation:devic-bounce 1.4s ease-in-out infinite both;background:var(--devic-text-muted);border-radius:50%;height:8px;width:8px}.devic-loading-dot:first-child{animation-delay:-.32s}.devic-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes devic-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.devic-tool-group{align-self:flex-start;display:flex;flex-direction:column;gap:2px;max-width:85%}.devic-tool-activity{align-items:flex-start;animation:devic-slideUp .3s ease-out;display:flex;gap:8px;padding:4px 0}.devic-tool-activity-icon{align-items:center;color:var(--devic-text-muted);display:flex;flex-shrink:0;margin-top:1px}.devic-tool-activity--active .devic-tool-activity-icon{color:var(--devic-primary)}.devic-tool-activity-text{color:var(--devic-text-secondary);font-size:13px;line-height:1.4}.devic-glow-text{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes devic-pulse{0%,to{opacity:1}50%{opacity:.5}}.devic-spinner{animation:devic-spin 1s linear infinite}@keyframes devic-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes devic-slideUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-tool-collapse-btn{align-items:center;background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:12px;gap:6px;padding:4px 0;transition:color .2s ease}.devic-tool-collapse-btn:hover{color:var(--devic-primary)}.devic-tool-group-items{animation:devic-expandItems .4s ease-out;overflow:hidden}.devic-tool-group-items[data-expanded=true]{max-height:500px}@keyframes devic-expandItems{0%{max-height:0;opacity:0}to{max-height:500px;opacity:1}}.devic-input-area{border-top:1px solid var(--devic-border);flex-shrink:0;padding:16px}.devic-input-wrapper{align-items:flex-end;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);display:flex;gap:8px;padding:8px 12px}.devic-input{background:none;border:none;color:var(--devic-text);flex:1;font-family:inherit;font-size:14px;line-height:1.5;max-height:120px;min-height:24px;outline:none;resize:none}.devic-input::placeholder{color:var(--devic-text-muted)}.devic-input-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;flex-shrink:0;padding:4px;transition:color var(--devic-transition)}.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-input-btn:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn{padding:6px 12px}.devic-send-btn,.devic-stop-btn{background:var(--devic-send-btn,var(--devic-primary));border-radius:var(--devic-radius-sm);color:#fff}.devic-stop-btn{align-items:center;display:flex;justify-content:center;padding:6px}.devic-stop-btn:hover{background:var(--devic-primary-hover);color:#fff}.devic-send-btn-wrapper{flex-shrink:0;position:relative}.devic-send-btn-custom{align-items:center;display:flex;justify-content:center;pointer-events:none}.devic-send-btn-overlay{background:transparent;border:none;cursor:pointer;inset:0;margin:0;padding:0;position:absolute}.devic-send-btn-overlay:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn:hover:not(:disabled){background:var(--devic-primary-hover);color:#fff}.devic-speech-error{background:#fff1f0;border:1px solid #ffccc7;border-radius:var(--devic-radius-sm);color:#cf1322;font-size:12px;margin-bottom:8px;padding:6px 10px}.devic-speech-mic.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-speech-panel{align-items:center;display:flex;flex:1;gap:8px;min-height:24px}.devic-speech-live{align-items:center;display:flex;flex:1;gap:10px;justify-content:flex-start}.devic-speech-timer{color:var(--devic-text-secondary);font-size:13px;font-variant-numeric:tabular-nums}.devic-speech-confirm{color:#389e0d}.devic-speech-confirm.devic-input-btn:hover:not(:disabled){color:#237804}.devic-speech-cancel{color:var(--devic-text-muted)}.devic-speech-cancel.devic-input-btn:hover:not(:disabled){color:#cf1322}.devic-speech-status{color:var(--devic-text-secondary);font-size:13px}.devic-speech-spinner{animation:devic-spin .8s linear infinite;border:2px solid var(--devic-border);border-radius:50%;border-top-color:var(--devic-primary);flex-shrink:0;height:16px;width:16px}.devic-transcript-playback{align-items:center;background:hsla(0,0%,100%,.18);border-radius:999px;display:inline-flex;font-size:12px;gap:6px;line-height:1;margin-top:6px;max-width:100%;padding:3px 8px 3px 3px}.devic-message[data-role=assistant] .devic-transcript-playback{background:var(--devic-bg-secondary,rgba(0,0,0,.05))}.devic-transcript-btn{align-items:center;background:hsla(0,0%,100%,.85);border:none;border-radius:50%;color:var(--devic-primary,#6c5ce7);cursor:pointer;display:inline-flex;flex-shrink:0;height:22px;justify-content:center;padding:0;transition:background .15s ease;width:22px}.devic-transcript-btn:hover:not(:disabled){background:#fff}.devic-transcript-btn:disabled{cursor:default;opacity:.7}.devic-transcript-icon{align-items:center;display:inline-flex;opacity:.85}.devic-transcript-playback[data-playing=true] .devic-transcript-icon{animation:devic-pulse 1.2s ease-in-out infinite}.devic-transcript-label{opacity:.9;white-space:nowrap}.devic-transcript-spinner{animation:devic-spin .8s linear infinite;border:2px solid rgba(108,92,231,.3);border-radius:50%;border-top:2px solid var(--devic-primary,#6c5ce7);height:12px;width:12px}.devic-equalizer{align-items:center;display:flex;gap:3px;height:24px}.devic-equalizer-bar{background:var(--devic-primary);border-radius:2px;min-height:3px;transition:height 90ms ease-out;width:3px}.devic-equalizer[data-paused=true] .devic-equalizer-bar{background:var(--devic-text-muted);height:10%!important}.devic-file-preview{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.devic-file-preview-item{align-items:center;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:4px 8px}.devic-file-remove{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;font-size:16px;line-height:1;padding:0}.devic-file-remove:hover{color:#ff4d4f}.devic-trigger{align-items:center;background:var(--devic-primary);border:none;border-radius:50%;box-shadow:var(--devic-shadow);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:background var(--devic-transition),transform var(--devic-transition);width:56px}.devic-trigger:hover{background:var(--devic-primary-hover);transform:scale(1.05)}.devic-trigger svg{height:24px;width:24px}.devic-error{background:#fff2f0;border:1px solid #ffccc7;border-radius:var(--devic-radius);color:#ff4d4f;font-size:13px;margin:8px 16px;padding:12px}.devic-messages-container::-webkit-scrollbar{width:6px}.devic-messages-container::-webkit-scrollbar-track{background:transparent}.devic-messages-container::-webkit-scrollbar-thumb{background:var(--devic-border);border-radius:3px}.devic-messages-container::-webkit-scrollbar-thumb:hover{background:var(--devic-text-muted)}.devic-chat-drawer[data-mode=inline]{border:1px solid var(--devic-border);bottom:auto;box-shadow:none;height:100%;left:auto;position:relative;right:auto;top:auto;transform:none}.devic-drawer-header-actions{align-items:center;display:flex;gap:4px;margin-left:auto}.devic-new-chat-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-new-chat-btn:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-selector{flex:1;margin:0 8px;min-width:0;position:relative}.devic-conversation-selector-trigger{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;gap:6px;padding:6px 10px;text-align:left;transition:border-color var(--devic-transition);width:100%}.devic-conversation-selector-trigger:hover{border-color:var(--devic-primary)}.devic-conversation-selector-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-dropdown{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius);box-shadow:var(--devic-shadow);display:flex;flex-direction:column;left:0;max-height:320px;position:absolute;right:0;top:calc(100% + 4px);z-index:10}.devic-conversation-search-wrapper{border-bottom:1px solid var(--devic-border);padding:8px}.devic-conversation-search{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);box-sizing:border-box;color:var(--devic-text);font-family:var(--devic-font-family);font-size:13px;outline:none;padding:6px 8px;width:100%}.devic-conversation-search:focus{border-color:var(--devic-primary)}.devic-conversation-list{flex:1;overflow-y:auto}.devic-conversation-item{align-items:center;background:none;border:none;color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;justify-content:space-between;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-item:hover,.devic-conversation-item[data-active=true]{background:var(--devic-bg-secondary)}.devic-conversation-item-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-item-date{color:var(--devic-text-muted);flex-shrink:0;font-size:11px;margin-left:8px}.devic-conversation-empty,.devic-conversation-loading{color:var(--devic-text-muted);font-size:13px;padding:12px;text-align:center}.devic-conversation-load-more{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:12px;padding:8px 12px;text-align:center;transition:background .15s;width:100%}.devic-conversation-load-more:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-new{background:none;border:none;border-top:1px solid var(--devic-border);color:var(--devic-primary);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:13px;padding:10px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-new:hover{background:var(--devic-bg-secondary)}.devic-conversation-item-check{align-items:center;color:var(--devic-primary);display:flex;flex-shrink:0;margin-right:6px}.devic-message-bubble h1,.devic-message-bubble h2,.devic-message-bubble h3,.devic-message-bubble h4,.devic-message-bubble h5,.devic-message-bubble h6{line-height:1.3;margin:8px 0 4px}.devic-message-bubble h1{font-size:1.3em}.devic-message-bubble h2{font-size:1.2em}.devic-message-bubble h3{font-size:1.1em}.devic-message-bubble p{margin:4px 0}.devic-message-bubble ol,.devic-message-bubble ul{margin:4px 0;padding-left:20px}.devic-message-bubble code{background:rgba(0,0,0,.06);border-radius:3px;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:.9em;padding:1px 4px}.devic-message-bubble pre{background:rgba(0,0,0,.06);border-radius:var(--devic-radius-sm);margin:8px 0;overflow-x:auto;padding:10px}.devic-message-bubble pre code{background:none;padding:0}.devic-message-bubble blockquote{border-left:3px solid var(--devic-border);color:var(--devic-text-secondary);margin:4px 0;padding-left:12px}.devic-message-bubble a{color:var(--devic-primary);text-decoration:underline}.markdown-table{margin:8px 0;overflow-x:auto}.markdown-table table{border-collapse:collapse;font-size:13px;width:100%}.markdown-table td,.markdown-table th{border:1px solid var(--devic-border);padding:6px 10px;text-align:left}.markdown-table th{background:var(--devic-bg-secondary);font-weight:600}.devic-resize-handle{bottom:0;cursor:col-resize;position:absolute;top:0;width:6px;z-index:1}.devic-resize-handle[data-position=right]{left:0}.devic-resize-handle[data-position=left]{right:0}.devic-resize-handle:active,.devic-resize-handle:hover{background:var(--devic-primary);opacity:.3}.devic-handoff-widget{animation:devic-slideUp .3s ease-out;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:8px;display:flex;flex-direction:column;gap:10px;max-width:320px;padding:12px;width:100%}.devic-handoff-header{align-items:center;display:flex;gap:8px}.devic-handoff-agent-avatar{align-items:center;background:var(--devic-bg-secondary);border-radius:50%;display:flex;flex-shrink:0;height:24px;justify-content:center;overflow:hidden;width:24px}.devic-handoff-avatar-img{height:100%;object-fit:cover;width:100%}.devic-handoff-agent-name{color:var(--devic-text);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-handoff-progress,.devic-handoff-state-row{align-items:center;display:flex;gap:8px}.devic-handoff-progress-bar{background:#f0f0f0;border-radius:3px;flex:1;height:6px;overflow:hidden;position:relative}.devic-handoff-progress-fill{border-radius:3px;height:100%;transition:width .4s ease}.devic-handoff-progress-fill[data-status=active]{background:var(--devic-primary)}.devic-handoff-progress-fill[data-status=success]{background:#52c41a}.devic-handoff-progress-fill[data-status=error]{background:#ff4d4f}.devic-handoff-progress-text{color:var(--devic-text-muted);flex-shrink:0;font-size:11px}.devic-handoff-progress-indeterminate{animation:devic-indeterminate 1.5s ease-in-out infinite;background:var(--devic-primary);border-radius:3px;height:100%;width:40%}@keyframes devic-indeterminate{0%{transform:translateX(-100%)}50%{transform:translateX(150%)}to{transform:translateX(-100%)}}.devic-handoff-summary{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:var(--devic-text-secondary);display:-webkit-box;font-size:12px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.devic-handoff-summary-active{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}.devic-handoff-elapsed{align-items:center;color:var(--devic-text-muted);display:flex;font-size:11px;gap:4px}.devic-message[data-role=user] .devic-message-references{display:flex;flex-wrap:wrap;gap:4px;justify-content:flex-end;margin-bottom:4px}.devic-message-reference-chip{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:999px;color:var(--devic-text);display:inline-flex;font-size:11px;gap:4px;max-width:220px;padding:3px 8px}.devic-message-reference-chip-label{color:var(--devic-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-reference-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:4px;padding:6px 8px}.devic-reference-chip{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:999px;color:var(--devic-text);display:inline-flex;font-size:12px;gap:6px;max-width:220px;padding:4px 8px}.devic-reference-chip-label{color:var(--devic-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-reference-chip-remove{align-items:center;background:transparent;border:none;border-radius:4px;color:var(--devic-text-muted);cursor:pointer;display:inline-flex;font-size:16px;line-height:1;padding:0 2px}.devic-reference-chip-remove:hover{background:rgba(0,0,0,.06);color:var(--devic-text)}.devic-input-disabled-notice{align-items:center;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);color:var(--devic-text-muted);display:flex;font-size:12px;gap:6px;justify-content:center;margin-bottom:4px;padding:8px 12px}.devic-inline-widgets{display:flex;flex-direction:column;gap:8px;padding:8px 12px}.devic-inline-widget{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius);padding:12px}.devic-input-widget{padding:8px;width:100%}@media (max-width:480px){.devic-chat-drawer{width:100%}}.devic-command-bar-container{--devic-cmd-bg:var(--devic-cmd-bg-override,#fff);--devic-cmd-text:var(--devic-cmd-text-override,#1f2937);--devic-cmd-text-secondary:var(--devic-cmd-text-secondary-override,#6b7280);--devic-cmd-border:var(--devic-cmd-border-override,#e5e7eb);--devic-cmd-radius:var(--devic-cmd-radius-override,12px);--devic-cmd-shadow:var(--devic-cmd-shadow-override,0 4px 20px rgba(0,0,0,.1));--devic-cmd-primary:var(--devic-cmd-primary-override,#3b82f6);--devic-cmd-font-family:var(--devic-cmd-font-family-override,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);--devic-cmd-font-size:var(--devic-cmd-font-size-override,14px);--devic-cmd-animation-duration:var(--devic-cmd-animation-duration-override,200ms);color:var(--devic-cmd-text);display:flex;flex-direction:column;font-family:var(--devic-cmd-font-family);font-size:var(--devic-cmd-font-size);gap:8px;max-width:100%;width:400px}.devic-command-bar-container[data-position=fixed]{position:fixed}.devic-command-bar-container[data-position=inline]{position:relative}.devic-command-bar-container[data-visible=false]{opacity:0;pointer-events:none;transform:translateY(8px)}.devic-command-bar-container[data-visible=false],.devic-command-bar-container[data-visible=true]{transition:opacity var(--devic-cmd-animation-duration) ease,transform var(--devic-cmd-animation-duration) ease}.devic-command-bar-container[data-visible=true]{opacity:1;transform:translateY(0)}.devic-command-bar{align-items:center;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);display:flex;gap:12px;padding:12px 16px}.devic-command-bar-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:20px;justify-content:center;width:20px}.devic-command-bar-icon svg{height:100%;width:100%}.devic-command-bar-input{background:transparent;border:none;color:inherit;flex:1;font-family:inherit;font-size:inherit;min-width:0;outline:none}.devic-command-bar-input::placeholder{color:var(--devic-cmd-text-secondary)}.devic-command-bar-summary{animation:devic-cmd-pulse 1.5s ease-in-out infinite;color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@keyframes devic-cmd-pulse{0%,to{opacity:1}50%{opacity:.6}}.devic-command-bar-shortcut{background:var(--devic-cmd-border);border-radius:6px;color:var(--devic-cmd-text-secondary);flex-shrink:0;font-size:12px;font-weight:500;letter-spacing:.5px;padding:4px 8px}.devic-command-bar-spinner{animation:devic-cmd-spin .8s linear infinite;border:2px solid var(--devic-cmd-border);border-radius:50%;border-top-color:var(--devic-cmd-primary);height:20px;width:20px}@keyframes devic-cmd-spin{to{transform:rotate(1turn)}}.devic-command-bar-result{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}@keyframes devic-cmd-slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-command-bar-result-tools{border-bottom:1px solid var(--devic-cmd-border)}.devic-command-bar-result-tools-header{align-items:center;color:var(--devic-cmd-text-secondary);cursor:pointer;display:flex;font-size:13px;gap:8px;padding:10px 14px;transition:background .15s ease;user-select:none}.devic-command-bar-result-tools-header:hover{background:rgba(0,0,0,.02)}.devic-command-bar-result-tools-chevron{height:16px;transition:transform .2s ease;width:16px}.devic-command-bar-result-tools-header[data-expanded=true] .devic-command-bar-result-tools-chevron{transform:rotate(90deg)}.devic-command-bar-result-tools-count{align-items:center;background:var(--devic-cmd-primary);border-radius:10px;color:#fff;display:inline-flex;font-size:11px;font-weight:600;height:20px;justify-content:center;min-width:20px;padding:0 6px}.devic-command-bar-result-tools-list{display:flex;flex-direction:column;gap:6px;padding:8px 14px 12px}.devic-command-bar-result-tools-list[data-expanded=false]{display:none}.devic-command-bar-result-tool-item{align-items:center;background:rgba(0,0,0,.02);border-radius:6px;display:flex;font-size:12px;gap:8px;padding:6px 10px}.devic-command-bar-result-tool-icon{color:#10b981;height:14px;width:14px}.devic-command-bar-result-tool-name{color:var(--devic-cmd-text-secondary)}.devic-command-bar-result-message{line-height:1.5;max-height:300px;overflow-y:auto;padding:14px}.devic-command-bar-result-message::-webkit-scrollbar{width:6px}.devic-command-bar-result-message::-webkit-scrollbar-track{background:transparent}.devic-command-bar-result-message::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-error{background:#fef2f2;border:1px solid #fecaca;border-radius:var(--devic-cmd-radius);color:#dc2626;font-size:13px;padding:10px 14px}.devic-command-bar-result-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:14px;text-align:center}.devic-command-bar-dropdown{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}.devic-command-bar-dropdown-header{align-items:center;border-bottom:1px solid var(--devic-cmd-border);color:var(--devic-cmd-text-secondary);display:flex;font-size:12px;font-weight:600;justify-content:space-between;letter-spacing:.5px;padding:10px 14px;text-transform:uppercase}.devic-command-bar-dropdown-hint{align-items:center;display:flex;font-weight:400;gap:4px;letter-spacing:0;text-transform:none}.devic-command-bar-dropdown-hint kbd{align-items:center;background:var(--devic-cmd-border);border-radius:4px;display:inline-flex;font-family:inherit;font-size:10px;height:18px;justify-content:center;min-width:18px;padding:0 4px}.devic-command-bar-dropdown-clear{background:none;border:none;border-radius:4px;color:var(--devic-cmd-primary);cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;letter-spacing:0;padding:2px 6px;text-transform:none}.devic-command-bar-dropdown-clear:hover{background:rgba(0,0,0,.05)}.devic-command-bar-dropdown-list{max-height:250px;overflow-y:auto}.devic-command-bar-dropdown-list::-webkit-scrollbar{width:6px}.devic-command-bar-dropdown-list::-webkit-scrollbar-track{background:transparent}.devic-command-bar-dropdown-list::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-dropdown-item{align-items:center;cursor:pointer;display:flex;gap:10px;padding:10px 14px;transition:background .15s ease}.devic-command-bar-dropdown-item:hover,.devic-command-bar-dropdown-item[data-selected=true]{background:rgba(0,0,0,.04)}.devic-command-bar-dropdown-item[data-selected=true]{background:var(--devic-cmd-primary);background:rgba(59,130,246,.1)}.devic-command-bar-dropdown-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:16px;justify-content:center;width:16px}.devic-command-bar-dropdown-keyword{color:var(--devic-cmd-text);flex-shrink:0;font-weight:600}.devic-command-bar-dropdown-desc{color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-command-bar-dropdown-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:20px 14px;text-align:center}.devic-command-bar-history-item{border-bottom:1px solid rgba(0,0,0,.04)}.devic-command-bar-history-item:last-child{border-bottom:none}.devic-command-bar-history-text{flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-gen-container{--devic-gen-primary:var(--devic-gen-primary-override,#3b82f6);--devic-gen-primary-hover:var(--devic-gen-primary-hover-override,#2563eb);--devic-gen-bg:var(--devic-gen-bg-override,#fff);--devic-gen-text:var(--devic-gen-text-override,#1f2937);--devic-gen-text-secondary:var(--devic-gen-text-secondary-override,#6b7280);--devic-gen-border:var(--devic-gen-border-override,#e5e7eb);--devic-gen-radius:var(--devic-gen-radius-override,8px);--devic-gen-font-family:var(--devic-gen-font-family-override,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);--devic-gen-font-size:var(--devic-gen-font-size-override,14px);--devic-gen-z-index:var(--devic-gen-z-index-override,10000);--devic-gen-animation-duration:var(--devic-gen-animation-duration-override,200ms);--devic-gen-modal-bg:var(--devic-gen-modal-bg-override,#fff);--devic-gen-modal-text:var(--devic-gen-modal-text-override,#1f2937);--devic-gen-modal-border:var(--devic-gen-modal-border-override,#e5e7eb);font-family:var(--devic-gen-font-family);font-size:var(--devic-gen-font-size)}.devic-gen-button{align-items:center;border:none;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-weight:500;gap:8px;justify-content:center;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-button:disabled{cursor:not-allowed;opacity:.6}.devic-gen-button[data-size=small]{font-size:12px;padding:6px 12px}.devic-gen-button[data-size=medium]{font-size:14px;padding:8px 16px}.devic-gen-button[data-size=large]{font-size:16px;padding:12px 24px}.devic-gen-button[data-variant=primary]{background:var(--devic-gen-primary);color:#fff}.devic-gen-button[data-variant=primary]:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-button[data-variant=secondary]{background:var(--devic-gen-border);color:var(--devic-gen-text)}.devic-gen-button[data-variant=secondary]:hover:not(:disabled){background:#d1d5db}.devic-gen-button[data-variant=outline]{background:transparent;border:1px solid var(--devic-gen-primary);color:var(--devic-gen-primary)}.devic-gen-button[data-variant=outline]:hover:not(:disabled){background:rgba(59,130,246,.1)}.devic-gen-button[data-variant=ghost]{background:transparent;color:var(--devic-gen-text)}.devic-gen-button[data-variant=ghost]:hover:not(:disabled){background:rgba(0,0,0,.05)}.devic-gen-button-icon{align-items:center;display:flex;height:16px;justify-content:center;width:16px}.devic-gen-button-icon svg{height:100%;width:100%}.devic-gen-spinner{animation:devic-gen-spin .8s linear infinite;border:2px solid;border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}.devic-gen-spinner-small{border-width:1.5px;height:12px;width:12px}@keyframes devic-gen-spin{to{transform:rotate(1turn)}}.devic-gen-input{background:var(--devic-gen-modal-bg);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);color:var(--devic-gen-modal-text);font-family:inherit;font-size:inherit;min-height:80px;outline:none;padding:12px;resize:vertical;transition:border-color var(--devic-gen-animation-duration) ease;width:100%}.devic-gen-input:focus{border-color:var(--devic-gen-primary)}.devic-gen-input::placeholder{color:var(--devic-gen-text-secondary)}.devic-gen-error{background:#fef2f2;border:1px solid #fecaca;border-radius:var(--devic-gen-radius);color:#dc2626;font-size:13px;margin-top:8px;padding:8px 12px}.devic-gen-tooltip{animation:devic-gen-fade-in var(--devic-gen-animation-duration) ease-out;background:var(--devic-gen-modal-bg);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);box-shadow:0 4px 20px rgba(0,0,0,.15);padding:12px}@keyframes devic-gen-fade-in{0%{opacity:0;transform:translateY(4px) translateX(-50%)}to{opacity:1;transform:translateY(0) translateX(-50%)}}.devic-gen-tooltip[data-placement=left],.devic-gen-tooltip[data-placement=right]{animation-name:devic-gen-fade-in-horizontal}@keyframes devic-gen-fade-in-horizontal{0%{opacity:0;transform:translateX(4px) translateY(-50%)}to{opacity:1;transform:translateX(0) translateY(-50%)}}.devic-gen-tooltip-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:12px}.devic-gen-tooltip-cancel,.devic-gen-tooltip-confirm{align-items:center;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-tooltip-cancel{background:transparent;border:1px solid var(--devic-gen-modal-border);color:var(--devic-gen-text-secondary)}.devic-gen-tooltip-cancel:hover{background:rgba(0,0,0,.05)}.devic-gen-tooltip-confirm{background:var(--devic-gen-primary);border:none;color:#fff}.devic-gen-tooltip-confirm:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-tooltip-confirm:disabled{cursor:not-allowed;opacity:.6}.devic-gen-modal-overlay{align-items:center;animation:devic-gen-overlay-fade-in var(--devic-gen-animation-duration) ease-out;background:rgba(0,0,0,.5);display:flex;inset:0;justify-content:center;position:fixed;z-index:var(--devic-gen-z-index)}@keyframes devic-gen-overlay-fade-in{0%{opacity:0}to{opacity:1}}.devic-gen-modal{animation:devic-gen-modal-slide-up var(--devic-gen-animation-duration) ease-out;background:var(--devic-gen-modal-bg);border-radius:calc(var(--devic-gen-radius) + 4px);box-shadow:0 20px 50px rgba(0,0,0,.2);margin:16px;max-width:480px;width:100%}@keyframes devic-gen-modal-slide-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.devic-gen-modal-header{align-items:center;border-bottom:1px solid var(--devic-gen-modal-border);display:flex;justify-content:space-between;padding:16px 20px}.devic-gen-modal-title{color:var(--devic-gen-modal-text);font-size:18px;font-weight:600;margin:0}.devic-gen-modal-close{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--devic-gen-text-secondary);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all var(--devic-gen-animation-duration) ease;width:32px}.devic-gen-modal-close:hover{background:rgba(0,0,0,.05);color:var(--devic-gen-modal-text)}.devic-gen-modal-description{color:var(--devic-gen-text-secondary);font-size:14px;line-height:1.5;margin:0;padding:12px 20px 0}.devic-gen-modal-body{padding:16px 20px}.devic-gen-modal-footer{border-top:1px solid var(--devic-gen-modal-border);display:flex;gap:12px;justify-content:flex-end;padding:16px 20px}.devic-gen-modal-cancel,.devic-gen-modal-confirm{align-items:center;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-modal-cancel{background:transparent;border:1px solid var(--devic-gen-modal-border);color:var(--devic-gen-text-secondary)}.devic-gen-modal-cancel:hover{background:rgba(0,0,0,.05);color:var(--devic-gen-modal-text)}.devic-gen-modal-confirm{background:var(--devic-gen-primary);border:none;color:#fff}.devic-gen-modal-confirm:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-modal-confirm:disabled{cursor:not-allowed;opacity:.6}.devic-gen-input::-webkit-scrollbar{width:6px}.devic-gen-input::-webkit-scrollbar-track{background:transparent}.devic-gen-input::-webkit-scrollbar-thumb{background:var(--devic-gen-border);border-radius:3px}.devic-gen-input:disabled{background:var(--devic-gen-border);cursor:not-allowed;opacity:.6}.devic-gen-tool-calls{background:rgba(0,0,0,.02);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);display:flex;flex-direction:column;gap:6px;margin-bottom:12px;padding:10px 12px}.devic-gen-tool-item{align-items:center;color:var(--devic-gen-text-secondary);display:flex;font-size:13px;gap:8px}.devic-gen-tool-item[data-status=executing]{color:var(--devic-gen-primary)}.devic-gen-tool-item[data-status=completed] .devic-gen-tool-icon{color:#10b981}.devic-gen-tool-icon{align-items:center;display:flex;flex-shrink:0;height:16px;justify-content:center;width:16px}.devic-gen-tool-icon svg{height:100%;width:100%}.devic-gen-tool-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-gen-tool-custom{padding:8px 0}.devic-gen-processing-status{align-items:center;background:rgba(59,130,246,.05);border:1px solid rgba(59,130,246,.2);border-radius:var(--devic-gen-radius);display:flex;gap:8px;margin-bottom:12px;padding:10px 12px}.devic-gen-processing-text{animation:devic-gen-pulse 1.5s ease-in-out infinite;color:var(--devic-gen-primary);font-size:13px}@keyframes devic-gen-pulse{0%,to{opacity:1}50%{opacity:.6}}.devic-aiwrap-container,.devic-aiwrap-tooltip,.devic-aiwrap-trigger-wrapper{--devic-aiwrap-color:#7c3aed;--devic-aiwrap-color-2:#4f46e5;--devic-aiwrap-bg:#fff;--devic-aiwrap-text:#1f2937;--devic-aiwrap-border:#e5e7eb;--devic-aiwrap-shadow:0 8px 24px rgba(0,0,0,.12)}.devic-aiwrap-container[data-highlight=true] .devic-aiwrap-content{background:rgba(124,58,237,.08);border-radius:4px;outline:1px dashed rgba(124,58,237,.45);outline-offset:2px;transition:background .15s ease,outline-color .15s ease}.devic-aiwrap-content{display:inline;transition:background .15s ease}.devic-aiwrap-trigger-wrapper{display:inline-flex}.devic-aiwrap-trigger{align-items:center;background:linear-gradient(90deg,var(--devic-aiwrap-color) 0,var(--devic-aiwrap-color-2) 100%);border:1px solid hsla(0,0%,100%,.25);box-shadow:0 4px 14px rgba(124,58,237,.35);color:#fff;cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:transform .12s ease,box-shadow .12s ease;white-space:nowrap}.devic-aiwrap-trigger:hover{box-shadow:0 6px 18px rgba(124,58,237,.45);transform:translateY(-1px)}.devic-aiwrap-trigger:active{transform:translateY(0)}.devic-aiwrap-trigger-icon{align-items:center;display:inline-flex}.devic-aiwrap-trigger-label{line-height:1}.devic-aiwrap-tooltip{background:var(--devic-aiwrap-bg);border:1px solid var(--devic-aiwrap-border);border-radius:12px;box-shadow:var(--devic-aiwrap-shadow);color:var(--devic-aiwrap-text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;overflow:hidden}.devic-aiwrap-tooltip-header{align-items:center;background:rgba(124,58,237,.05);border-bottom:1px solid var(--devic-aiwrap-border);display:flex;gap:8px;justify-content:space-between;padding:10px 12px}.devic-aiwrap-tooltip-label{color:var(--devic-aiwrap-color);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-aiwrap-tooltip-close{align-items:center;background:transparent;border:none;border-radius:4px;color:#6b7280;cursor:pointer;display:inline-flex;padding:2px}.devic-aiwrap-tooltip-close:hover{background:rgba(0,0,0,.06);color:#111827}.devic-aiwrap-tooltip-body{line-height:1.5;max-height:320px;overflow-y:auto;padding:12px}.devic-aiwrap-processing{align-items:center;color:#6b7280;display:flex;font-size:13px;gap:8px}.devic-aiwrap-spinner{animation:devic-aiwrap-spin .7s linear infinite;border:2px solid rgba(124,58,237,.25);border-radius:50%;border-top:2px solid var(--devic-aiwrap-color);flex-shrink:0;height:14px;width:14px}@keyframes devic-aiwrap-spin{to{transform:rotate(1turn)}}.devic-aiwrap-error{color:#dc2626;font-size:13px}.devic-aiwrap-answer{white-space:pre-wrap;word-break:break-word}
1
+ .devic-state-tag{align-items:center;border:1px solid;border-radius:4px;cursor:default;display:inline-flex;font-family:var(--devic-font-family,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);font-size:12px;font-weight:500;gap:6px;line-height:20px;padding:2px 8px;position:relative;white-space:nowrap}.devic-state-tag[data-interactive=true]{cursor:pointer}.devic-state-tag[data-interactive=true]:hover{opacity:.85}.devic-state-tag[data-color=gold]{background:rgba(250,173,20,.15);border-color:rgba(250,173,20,.35);color:#faad14}.devic-state-tag[data-color=processing]{background:rgba(22,119,255,.15);border-color:rgba(22,119,255,.35);color:#4096ff}.devic-state-tag[data-color=success]{background:rgba(82,196,26,.15);border-color:rgba(82,196,26,.35);color:#52c41a}.devic-state-tag[data-color=error]{background:rgba(255,77,79,.15);border-color:rgba(255,77,79,.35);color:#ff4d4f}.devic-state-tag[data-color=default]{background:hsla(0,0%,60%,.15);border-color:hsla(0,0%,60%,.35);color:#999}.devic-state-tag[data-color=purple]{background:rgba(114,46,209,.15);border-color:rgba(114,46,209,.35);color:#b37feb}.devic-state-tag[data-color=blue]{background:rgba(22,119,255,.15);border-color:rgba(22,119,255,.35);color:#4096ff}.devic-state-tag-icon{align-items:center;display:inline-flex;flex-shrink:0}.devic-state-tag-caret{align-items:center;display:inline-flex;margin-left:2px;transition:transform .2s ease}.devic-state-tag[data-dropdown-open=true] .devic-state-tag-caret{transform:rotate(180deg)}.devic-state-spinner{animation:devic-state-spin 1s linear infinite}@keyframes devic-state-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.devic-state-tooltip{background:rgba(0,0,0,.85);border-radius:6px;bottom:calc(100% + 8px);color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:400;line-height:1.4;max-width:280px;padding:6px 10px;pointer-events:none;white-space:normal;z-index:1060}.devic-state-tooltip,.devic-state-tooltip:after{left:50%;position:absolute;transform:translateX(-50%)}.devic-state-tooltip:after{border:5px solid transparent;border-top-color:rgba(0,0,0,.85);content:"";top:100%}.devic-state-dropdown{animation:devic-dropdownSlide .15s ease-out;background:#fff;border:1px solid #e8e8e8;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08),0 3px 6px rgba(0,0,0,.06);min-width:180px;padding:4px 0;position:absolute;right:0;top:calc(100% + 4px);z-index:1050}@keyframes devic-dropdownSlide{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.devic-state-dropdown-item{align-items:center;background:none;border:none;color:#333;cursor:pointer;display:flex;font-family:inherit;font-size:13px;gap:8px;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-state-dropdown-item:hover{background:#f5f5f5}.devic-state-dropdown-item-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center;width:18px}.devic-state-tooltip-portal{background:rgba(0,0,0,.85);border-radius:6px;color:#fff;font-family:SFMono-Regular,Consolas,monospace;font-size:12px;font-weight:400;line-height:1.4;max-width:280px;padding:6px 10px;pointer-events:none;white-space:normal;z-index:99999}.devic-state-dropdown-portal{animation:devic-dropdownSlide .15s ease-out;background:#fff;border:1px solid #e8e8e8;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08),0 3px 6px rgba(0,0,0,.06);min-width:180px;padding:4px 0;z-index:99999}.devic-state-modal-overlay{align-items:center;animation:devic-fadeIn .2s ease;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;position:fixed;z-index:1050}@keyframes devic-fadeIn{0%{opacity:0}to{opacity:1}}.devic-state-modal{animation:devic-modalSlide .2s ease-out;background:#fff;border-radius:8px;box-shadow:0 6px 16px rgba(0,0,0,.08);display:flex;flex-direction:column;max-height:80vh;max-width:520px;width:90%}@keyframes devic-modalSlide{0%{opacity:0;transform:translateY(-16px)}to{opacity:1;transform:translateY(0)}}.devic-state-modal-header{align-items:center;border-bottom:1px solid #f0f0f0;display:flex;justify-content:space-between;padding:16px 20px}.devic-state-modal-title{align-items:center;display:flex;font-size:16px;font-weight:600;gap:8px;margin:0}.devic-state-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:#999;cursor:pointer;display:flex;padding:4px}.devic-state-modal-close:hover{background:#f5f5f5;color:#333}.devic-state-modal-body{flex:1;overflow-y:auto;padding:20px}.devic-state-modal-footer{border-top:1px solid #f0f0f0;display:flex;gap:8px;justify-content:flex-end;padding:12px 20px}.devic-state-btn{align-items:center;background:#fff;border:1px solid #d9d9d9;border-radius:6px;color:#333;cursor:pointer;display:inline-flex;font-family:inherit;font-size:14px;font-weight:500;gap:6px;justify-content:center;padding:6px 16px;transition:all .2s}.devic-state-btn:hover{border-color:#1677ff;color:#1677ff}.devic-state-btn-primary{background:#1677ff;border-color:#1677ff;color:#fff}.devic-state-btn-primary:hover{background:#4096ff;border-color:#4096ff;color:#fff}.devic-state-btn-danger{background:#ff4d4f;border-color:#ff4d4f;color:#fff}.devic-state-btn-danger:hover{background:#ff7875;border-color:#ff7875;color:#fff}.devic-state-btn-success{background:#52c41a;border-color:#52c41a;color:#fff}.devic-state-btn-success:hover{background:#73d13d;border-color:#73d13d;color:#fff}.devic-state-btn:disabled{cursor:not-allowed;opacity:.5}.devic-explain-content{border:1px solid #e8e8e8;border-radius:8px;font-family:SFMono-Regular,Consolas,monospace;font-size:13px;line-height:1.6;max-height:300px;min-height:150px;overflow-y:auto;padding:12px;white-space:pre-wrap}.devic-typing-cursor{animation:devic-blink 1s step-end infinite}@keyframes devic-blink{0%,to{opacity:1}50%{opacity:0}}.devic-approval-layout{display:flex;gap:16px}.devic-approval-request{background:#fafafa;border:1px solid #e8e8e8;border-radius:8px;flex:1;font-size:13px;line-height:1.6;max-height:250px;overflow-y:auto;padding:12px}.devic-approval-actions{display:flex;flex:1;flex-direction:column;gap:12px}.devic-approval-textarea{border:1px solid #d9d9d9;border-radius:6px;box-sizing:border-box;font-family:inherit;font-size:13px;min-height:80px;outline:none;padding:8px 12px;resize:vertical;width:100%}.devic-approval-textarea:focus{border-color:#1677ff}.devic-approval-buttons{display:flex;flex-direction:column;gap:8px}.devic-completion-select{background:#fff;border:1px solid #d9d9d9;border-radius:6px;cursor:pointer;font-family:inherit;font-size:14px;outline:none;padding:8px 12px;width:100%}.devic-completion-select:focus{border-color:#1677ff}.devic-state-loading{align-items:center;display:flex;justify-content:center;padding:24px}.devic-state-loading-spinner{animation:devic-state-spin .8s linear infinite;border:2px solid #f0f0f0;border-radius:50%;border-top-color:#1677ff;height:24px;width:24px}.devic-state-warning{align-items:flex-start;color:#cf1322;display:flex;font-size:13px;font-weight:500;gap:6px;margin-top:8px}.devic-message-actions{align-items:center;display:flex;gap:4px;opacity:0;transition:opacity .15s ease}.devic-message-actions:focus-within,.devic-message:hover .devic-message-actions{opacity:1}.devic-message-actions:has(.devic-action-btn--active){opacity:1}.devic-action-btn{align-items:center;background:transparent;border:none;border-radius:var(--devic-radius-sm,6px);color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-action-btn:hover:not(:disabled){background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-action-btn:disabled{cursor:not-allowed;opacity:.5}.devic-action-btn--active{color:var(--devic-primary,#3b82f6)}.devic-action-btn--active.devic-action-btn--positive{color:#22c55e}.devic-action-btn--active.devic-action-btn--negative{color:#ef4444}.devic-feedback-overlay{align-items:center;animation:devic-feedback-fade-in .15s ease;background:rgba(0,0,0,.4);bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:10001}@keyframes devic-feedback-fade-in{0%{opacity:0}to{opacity:1}}.devic-feedback-modal{animation:devic-feedback-slide-up .2s ease;background:var(--devic-bg,#fff);border-radius:var(--devic-radius,12px);box-shadow:0 20px 60px rgba(0,0,0,.2);margin:16px;max-width:400px;width:100%}@keyframes devic-feedback-slide-up{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.devic-feedback-modal-header{align-items:center;border-bottom:1px solid var(--devic-border,#e2e8f0);display:flex;gap:10px;padding:16px 16px 12px}.devic-feedback-modal-icon{align-items:center;background:var(--devic-bg-secondary,#f8fafc);border-radius:8px;color:var(--devic-text,#1e293b);display:flex;height:32px;justify-content:center;width:32px}.devic-feedback-modal-title{color:var(--devic-text,#1e293b);flex:1;font-size:15px;font-weight:600}.devic-feedback-modal-close{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--devic-text-muted,#94a3b8);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;transition:all .15s ease;width:28px}.devic-feedback-modal-close:hover{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-textarea{background:transparent;border:none;border-bottom:1px solid var(--devic-border,#e2e8f0);box-sizing:border-box;color:var(--devic-text,#1e293b);display:block;font-family:inherit;font-size:14px;line-height:1.5;padding:12px 16px;resize:none;width:100%}.devic-feedback-textarea:focus{outline:none}.devic-feedback-textarea::placeholder{color:var(--devic-text-muted,#94a3b8)}.devic-feedback-modal-actions{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px}.devic-feedback-btn{border:none;border-radius:var(--devic-radius-sm,6px);cursor:pointer;font-family:inherit;font-size:14px;font-weight:500;padding:8px 16px;transition:all .15s ease}.devic-feedback-btn:disabled{cursor:not-allowed;opacity:.6}.devic-feedback-btn--secondary{background:var(--devic-bg-secondary,#f8fafc);color:var(--devic-text-secondary,#64748b)}.devic-feedback-btn--secondary:hover:not(:disabled){background:var(--devic-border,#e2e8f0)}.devic-feedback-btn--primary{background:var(--devic-primary,#3b82f6);color:#fff}.devic-feedback-btn--primary:hover:not(:disabled){background:var(--devic-primary-hover,#2563eb)}.devic-cmd-result-actions{border-top:1px solid var(--devic-cmd-border,var(--devic-border,#e5e7eb));margin-top:8px;padding-top:8px}.devic-cmd-result-actions .devic-message-actions{opacity:1;padding-left:10px}.devic-cmd-result-actions .devic-action-btn{opacity:.7}.devic-cmd-result-actions .devic-action-btn--active,.devic-cmd-result-actions .devic-action-btn:hover{opacity:1}.devic-chat-drawer{--devic-primary:#1890ff;--devic-primary-hover:#40a9ff;--devic-primary-light:#e6f7ff;--devic-bg:#fff;--devic-bg-secondary:#f5f5f5;--devic-text:#333;--devic-text-secondary:#666;--devic-text-muted:#999;--devic-border:#e8e8e8;--devic-shadow:0 4px 12px rgba(0,0,0,.15);--devic-radius:8px;--devic-radius-sm:4px;--devic-radius-lg:16px;--devic-font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--devic-transition:0.3s ease;background:var(--devic-bg);bottom:0;box-shadow:var(--devic-shadow);color:var(--devic-text);display:flex;flex-direction:column;font-family:var(--devic-font-family);font-size:14px;line-height:1.5;position:fixed;top:0;transition:transform var(--devic-transition)}.devic-chat-drawer[data-position=right]{right:0;transform:translateX(100%)}.devic-chat-drawer[data-position=left]{left:0;transform:translateX(-100%)}.devic-chat-drawer[data-open=true]{transform:translateX(0)}.devic-drawer-overlay{background:rgba(0,0,0,.3);inset:0;opacity:0;position:fixed;transition:opacity var(--devic-transition),visibility var(--devic-transition);visibility:hidden}.devic-drawer-overlay[data-open=true]{opacity:1;visibility:visible}.devic-drawer-header{align-items:center;border-bottom:1px solid var(--devic-border);display:flex;flex-shrink:0;justify-content:space-between;padding:16px}.devic-drawer-avatar{border-radius:50%;flex-shrink:0;height:28px;object-fit:cover;width:28px}.devic-drawer-title{font-size:16px;font-weight:600;margin:0}.devic-drawer-close{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-drawer-close:hover{background:var(--devic-bg-secondary);color:var(--devic-text)}.devic-messages-container{display:flex;flex:1;flex-direction:column;gap:12px;overflow-y:auto;padding:16px}.devic-welcome{color:var(--devic-text-secondary);padding:24px 16px;text-align:center}.devic-welcome-text{font-size:16px;margin-bottom:16px}.devic-suggested-messages{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}.devic-suggested-btn{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-lg);color:var(--devic-text);cursor:pointer;font-size:13px;padding:8px 16px;transition:border-color var(--devic-transition),background var(--devic-transition)}.devic-suggested-btn:hover{background:var(--devic-primary-light);border-color:var(--devic-primary)}.devic-message{display:flex;flex-direction:column;max-width:85%}.devic-message[data-role=user]{align-self:flex-end}.devic-message[data-role=assistant],.devic-message[data-role=tool]{align-self:flex-start}.devic-message-bubble{word-wrap:break-word;border-radius:var(--devic-radius);padding:10px 14px}.devic-message[data-role=user] .devic-message-bubble{background:var(--devic-user-bubble,var(--devic-primary));border-bottom-right-radius:var(--devic-radius-sm);color:var(--devic-user-bubble-text,#fff)}.devic-message[data-role=assistant] .devic-message-bubble{background:var(--devic-assistant-bubble,var(--devic-bg-secondary));border-bottom-left-radius:var(--devic-radius-sm);color:var(--devic-assistant-bubble-text,var(--devic-text))}.devic-message[data-role=tool] .devic-message-bubble{background:var(--devic-primary-light);border:1px solid var(--devic-primary);color:var(--devic-text);font-size:12px}.devic-message-footer{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-top:4px}.devic-message-time{color:var(--devic-text-muted);font-size:11px}.devic-message[data-role=user] .devic-message-footer{justify-content:flex-end}.devic-message[data-role=user] .devic-message-time{text-align:right}.devic-message-files{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.devic-message-file{align-items:center;background:hsla(0,0%,100%,.2);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:6px 10px}.devic-loading{align-self:flex-start;display:flex;gap:4px;padding:10px 14px}.devic-loading-dot{animation:devic-bounce 1.4s ease-in-out infinite both;background:var(--devic-text-muted);border-radius:50%;height:8px;width:8px}.devic-loading-dot:first-child{animation-delay:-.32s}.devic-loading-dot:nth-child(2){animation-delay:-.16s}@keyframes devic-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.devic-tool-group{align-self:flex-start;display:flex;flex-direction:column;gap:2px;max-width:85%}.devic-tool-activity{align-items:flex-start;animation:devic-slideUp .3s ease-out;display:flex;gap:8px;padding:4px 0}.devic-tool-activity-icon{align-items:center;color:var(--devic-text-muted);display:flex;flex-shrink:0;margin-top:1px}.devic-tool-activity--active .devic-tool-activity-icon{color:var(--devic-primary)}.devic-tool-activity-text{color:var(--devic-text-secondary);font-size:13px;line-height:1.4}.devic-glow-text{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes devic-pulse{0%,to{opacity:1}50%{opacity:.5}}.devic-spinner{animation:devic-spin 1s linear infinite}@keyframes devic-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes devic-slideUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-tool-collapse-btn{align-items:center;background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:12px;gap:6px;padding:4px 0;transition:color .2s ease}.devic-tool-collapse-btn:hover{color:var(--devic-primary)}.devic-tool-group-items{animation:devic-expandItems .4s ease-out;overflow:hidden}.devic-tool-group-items[data-expanded=true]{max-height:500px}@keyframes devic-expandItems{0%{max-height:0;opacity:0}to{max-height:500px;opacity:1}}.devic-input-area{border-top:1px solid var(--devic-border);flex-shrink:0;padding:16px}.devic-input-wrapper{align-items:flex-end;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);display:flex;gap:8px;padding:8px 12px}.devic-input{background:none;border:none;color:var(--devic-text);flex:1;font-family:inherit;font-size:14px;line-height:1.5;max-height:120px;min-height:24px;outline:none;resize:none}.devic-input::placeholder{color:var(--devic-text-muted)}.devic-input-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;flex-shrink:0;padding:4px;transition:color var(--devic-transition)}.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-input-btn:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn{padding:6px 12px}.devic-send-btn,.devic-stop-btn{background:var(--devic-send-btn,var(--devic-primary));border-radius:var(--devic-radius-sm);color:#fff}.devic-stop-btn{align-items:center;display:flex;justify-content:center;padding:6px}.devic-stop-btn:hover{background:var(--devic-primary-hover);color:#fff}.devic-send-btn-wrapper{flex-shrink:0;position:relative}.devic-send-btn-custom{align-items:center;display:flex;justify-content:center;pointer-events:none}.devic-send-btn-overlay{background:transparent;border:none;cursor:pointer;inset:0;margin:0;padding:0;position:absolute}.devic-send-btn-overlay:disabled{cursor:not-allowed;opacity:.5}.devic-send-btn:hover:not(:disabled){background:var(--devic-primary-hover);color:#fff}.devic-speech-error{background:#fff1f0;border:1px solid #ffccc7;border-radius:var(--devic-radius-sm);color:#cf1322;font-size:12px;margin-bottom:8px;padding:6px 10px}.devic-speech-mic.devic-input-btn:hover:not(:disabled){color:var(--devic-primary)}.devic-speech-panel{align-items:center;display:flex;flex:1;gap:8px;min-height:24px}.devic-speech-live{align-items:center;display:flex;flex:1;gap:10px;justify-content:flex-start}.devic-speech-timer{color:var(--devic-text-secondary);font-size:13px;font-variant-numeric:tabular-nums}.devic-speech-confirm{color:#389e0d}.devic-speech-confirm.devic-input-btn:hover:not(:disabled){color:#237804}.devic-speech-confirm-wrap{align-items:center;display:inline-flex;flex-shrink:0;justify-content:center;position:relative}.devic-autostop-ring{height:calc(100% + 6px);inset:-3px;pointer-events:none;position:absolute;transform:rotate(-90deg);width:calc(100% + 6px)}.devic-autostop-ring-track{fill:none;stroke:#389e0d;stroke-opacity:.18;stroke-width:3}.devic-autostop-ring-progress{fill:none;stroke:#389e0d;stroke-width:3;stroke-linecap:round;transition:stroke-dashoffset 90ms linear}.devic-speech-confirm-wrap[data-autostop=true] .devic-speech-confirm{animation:devic-autostop-pulse 1s ease-in-out infinite}@keyframes devic-autostop-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.08)}}.devic-speech-cancel{color:var(--devic-text-muted)}.devic-speech-cancel.devic-input-btn:hover:not(:disabled){color:#cf1322}.devic-speech-status{color:var(--devic-text-secondary);font-size:13px}.devic-speech-spinner{animation:devic-spin .8s linear infinite;border:2px solid var(--devic-border);border-radius:50%;border-top-color:var(--devic-primary);flex-shrink:0;height:16px;width:16px}.devic-transcript-playback{align-items:center;background:hsla(0,0%,100%,.18);border-radius:999px;display:inline-flex;font-size:12px;gap:6px;line-height:1;margin-top:6px;max-width:100%;padding:3px 8px 3px 3px}.devic-message[data-role=assistant] .devic-transcript-playback{background:var(--devic-bg-secondary,rgba(0,0,0,.05))}.devic-transcript-btn{align-items:center;background:hsla(0,0%,100%,.85);border:none;border-radius:50%;color:var(--devic-primary,#6c5ce7);cursor:pointer;display:inline-flex;flex-shrink:0;height:22px;justify-content:center;padding:0;transition:background .15s ease;width:22px}.devic-transcript-btn:hover:not(:disabled){background:#fff}.devic-transcript-btn:disabled{cursor:default;opacity:.7}.devic-transcript-icon{align-items:center;display:inline-flex;opacity:.85}.devic-transcript-playback[data-playing=true] .devic-transcript-icon{animation:devic-pulse 1.2s ease-in-out infinite}.devic-transcript-label{opacity:.9;white-space:nowrap}.devic-transcript-spinner{animation:devic-spin .8s linear infinite;border:2px solid rgba(108,92,231,.3);border-radius:50%;border-top:2px solid var(--devic-primary,#6c5ce7);height:12px;width:12px}.devic-equalizer{align-items:center;display:flex;gap:3px;height:24px}.devic-equalizer-bar{background:var(--devic-primary);border-radius:2px;min-height:3px;transition:height 90ms ease-out;width:3px}.devic-equalizer[data-paused=true] .devic-equalizer-bar{background:var(--devic-text-muted);height:10%!important}.devic-file-preview{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.devic-file-preview-item{align-items:center;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);display:flex;font-size:12px;gap:6px;padding:4px 8px}.devic-file-remove{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;font-size:16px;line-height:1;padding:0}.devic-file-remove:hover{color:#ff4d4f}.devic-trigger{align-items:center;background:var(--devic-primary);border:none;border-radius:50%;box-shadow:var(--devic-shadow);color:#fff;cursor:pointer;display:flex;height:56px;justify-content:center;position:fixed;transition:background var(--devic-transition),transform var(--devic-transition);width:56px}.devic-trigger:hover{background:var(--devic-primary-hover);transform:scale(1.05)}.devic-trigger svg{height:24px;width:24px}.devic-error{background:#fff2f0;border:1px solid #ffccc7;border-radius:var(--devic-radius);color:#ff4d4f;font-size:13px;margin:8px 16px;padding:12px}.devic-messages-container::-webkit-scrollbar{width:6px}.devic-messages-container::-webkit-scrollbar-track{background:transparent}.devic-messages-container::-webkit-scrollbar-thumb{background:var(--devic-border);border-radius:3px}.devic-messages-container::-webkit-scrollbar-thumb:hover{background:var(--devic-text-muted)}.devic-chat-drawer[data-mode=inline]{border:1px solid var(--devic-border);bottom:auto;box-shadow:none;height:100%;left:auto;position:relative;right:auto;top:auto;transform:none}.devic-drawer-header-actions{align-items:center;display:flex;gap:4px;margin-left:auto}.devic-new-chat-btn{background:none;border:none;border-radius:var(--devic-radius-sm);color:var(--devic-text-secondary);cursor:pointer;padding:8px;transition:background var(--devic-transition),color var(--devic-transition)}.devic-new-chat-btn:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-selector{flex:1;margin:0 8px;min-width:0;position:relative}.devic-conversation-selector-trigger{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;gap:6px;padding:6px 10px;text-align:left;transition:border-color var(--devic-transition);width:100%}.devic-conversation-selector-trigger:hover{border-color:var(--devic-primary)}.devic-conversation-selector-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-dropdown{background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:var(--devic-radius);box-shadow:var(--devic-shadow);display:flex;flex-direction:column;left:0;max-height:320px;position:absolute;right:0;top:calc(100% + 4px);z-index:10}.devic-conversation-search-wrapper{border-bottom:1px solid var(--devic-border);padding:8px}.devic-conversation-search{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius-sm);box-sizing:border-box;color:var(--devic-text);font-family:var(--devic-font-family);font-size:13px;outline:none;padding:6px 8px;width:100%}.devic-conversation-search:focus{border-color:var(--devic-primary)}.devic-conversation-list{flex:1;overflow-y:auto}.devic-conversation-item{align-items:center;background:none;border:none;color:var(--devic-text);cursor:pointer;display:flex;font-family:var(--devic-font-family);font-size:13px;justify-content:space-between;padding:8px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-item:hover,.devic-conversation-item[data-active=true]{background:var(--devic-bg-secondary)}.devic-conversation-item-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-conversation-item-date{color:var(--devic-text-muted);flex-shrink:0;font-size:11px;margin-left:8px}.devic-conversation-empty,.devic-conversation-loading{color:var(--devic-text-muted);font-size:13px;padding:12px;text-align:center}.devic-conversation-load-more{background:none;border:none;color:var(--devic-text-muted);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:12px;padding:8px 12px;text-align:center;transition:background .15s;width:100%}.devic-conversation-load-more:hover{background:var(--devic-bg-secondary);color:var(--devic-primary)}.devic-conversation-new{background:none;border:none;border-top:1px solid var(--devic-border);color:var(--devic-primary);cursor:pointer;display:block;font-family:var(--devic-font-family);font-size:13px;padding:10px 12px;text-align:left;transition:background .15s;width:100%}.devic-conversation-new:hover{background:var(--devic-bg-secondary)}.devic-conversation-item-check{align-items:center;color:var(--devic-primary);display:flex;flex-shrink:0;margin-right:6px}.devic-message-bubble h1,.devic-message-bubble h2,.devic-message-bubble h3,.devic-message-bubble h4,.devic-message-bubble h5,.devic-message-bubble h6{line-height:1.3;margin:8px 0 4px}.devic-message-bubble h1{font-size:1.3em}.devic-message-bubble h2{font-size:1.2em}.devic-message-bubble h3{font-size:1.1em}.devic-message-bubble p{margin:4px 0}.devic-message-bubble ol,.devic-message-bubble ul{margin:4px 0;padding-left:20px}.devic-message-bubble code{background:rgba(0,0,0,.06);border-radius:3px;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:.9em;padding:1px 4px}.devic-message-bubble pre{background:rgba(0,0,0,.06);border-radius:var(--devic-radius-sm);margin:8px 0;overflow-x:auto;padding:10px}.devic-message-bubble pre code{background:none;padding:0}.devic-message-bubble blockquote{border-left:3px solid var(--devic-border);color:var(--devic-text-secondary);margin:4px 0;padding-left:12px}.devic-message-bubble a{color:var(--devic-primary);text-decoration:underline}.markdown-table{margin:8px 0;overflow-x:auto}.markdown-table table{border-collapse:collapse;font-size:13px;width:100%}.markdown-table td,.markdown-table th{border:1px solid var(--devic-border);padding:6px 10px;text-align:left}.markdown-table th{background:var(--devic-bg-secondary);font-weight:600}.devic-resize-handle{bottom:0;cursor:col-resize;position:absolute;top:0;width:6px;z-index:1}.devic-resize-handle[data-position=right]{left:0}.devic-resize-handle[data-position=left]{right:0}.devic-resize-handle:active,.devic-resize-handle:hover{background:var(--devic-primary);opacity:.3}.devic-handoff-widget{animation:devic-slideUp .3s ease-out;background:var(--devic-bg);border:1px solid var(--devic-border);border-radius:8px;display:flex;flex-direction:column;gap:10px;max-width:320px;padding:12px;width:100%}.devic-handoff-header{align-items:center;display:flex;gap:8px}.devic-handoff-agent-avatar{align-items:center;background:var(--devic-bg-secondary);border-radius:50%;display:flex;flex-shrink:0;height:24px;justify-content:center;overflow:hidden;width:24px}.devic-handoff-avatar-img{height:100%;object-fit:cover;width:100%}.devic-handoff-agent-name{color:var(--devic-text);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-handoff-progress,.devic-handoff-state-row{align-items:center;display:flex;gap:8px}.devic-handoff-progress-bar{background:#f0f0f0;border-radius:3px;flex:1;height:6px;overflow:hidden;position:relative}.devic-handoff-progress-fill{border-radius:3px;height:100%;transition:width .4s ease}.devic-handoff-progress-fill[data-status=active]{background:var(--devic-primary)}.devic-handoff-progress-fill[data-status=success]{background:#52c41a}.devic-handoff-progress-fill[data-status=error]{background:#ff4d4f}.devic-handoff-progress-text{color:var(--devic-text-muted);flex-shrink:0;font-size:11px}.devic-handoff-progress-indeterminate{animation:devic-indeterminate 1.5s ease-in-out infinite;background:var(--devic-primary);border-radius:3px;height:100%;width:40%}@keyframes devic-indeterminate{0%{transform:translateX(-100%)}50%{transform:translateX(150%)}to{transform:translateX(-100%)}}.devic-handoff-summary{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:var(--devic-text-secondary);display:-webkit-box;font-size:12px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.devic-handoff-summary-active{animation:devic-pulse 2s cubic-bezier(.4,0,.6,1) infinite}.devic-handoff-elapsed{align-items:center;color:var(--devic-text-muted);display:flex;font-size:11px;gap:4px}.devic-message[data-role=user] .devic-message-references{display:flex;flex-wrap:wrap;gap:4px;justify-content:flex-end;margin-bottom:4px}.devic-message-reference-chip{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:999px;color:var(--devic-text);display:inline-flex;font-size:11px;gap:4px;max-width:220px;padding:3px 8px}.devic-message-reference-chip-label{color:var(--devic-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-reference-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:4px;padding:6px 8px}.devic-reference-chip{align-items:center;background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:999px;color:var(--devic-text);display:inline-flex;font-size:12px;gap:6px;max-width:220px;padding:4px 8px}.devic-reference-chip-label{color:var(--devic-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-reference-chip-remove{align-items:center;background:transparent;border:none;border-radius:4px;color:var(--devic-text-muted);cursor:pointer;display:inline-flex;font-size:16px;line-height:1;padding:0 2px}.devic-reference-chip-remove:hover{background:rgba(0,0,0,.06);color:var(--devic-text)}.devic-input-disabled-notice{align-items:center;background:var(--devic-bg-secondary);border-radius:var(--devic-radius);color:var(--devic-text-muted);display:flex;font-size:12px;gap:6px;justify-content:center;margin-bottom:4px;padding:8px 12px}.devic-inline-widgets{display:flex;flex-direction:column;gap:8px;padding:8px 12px}.devic-inline-widget{background:var(--devic-bg-secondary);border:1px solid var(--devic-border);border-radius:var(--devic-radius);padding:12px}.devic-input-widget{padding:8px;width:100%}@media (max-width:480px){.devic-chat-drawer{width:100%}}.devic-command-bar-container{--devic-cmd-bg:var(--devic-cmd-bg-override,#fff);--devic-cmd-text:var(--devic-cmd-text-override,#1f2937);--devic-cmd-text-secondary:var(--devic-cmd-text-secondary-override,#6b7280);--devic-cmd-border:var(--devic-cmd-border-override,#e5e7eb);--devic-cmd-radius:var(--devic-cmd-radius-override,12px);--devic-cmd-shadow:var(--devic-cmd-shadow-override,0 4px 20px rgba(0,0,0,.1));--devic-cmd-primary:var(--devic-cmd-primary-override,#3b82f6);--devic-cmd-font-family:var(--devic-cmd-font-family-override,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);--devic-cmd-font-size:var(--devic-cmd-font-size-override,14px);--devic-cmd-animation-duration:var(--devic-cmd-animation-duration-override,200ms);color:var(--devic-cmd-text);display:flex;flex-direction:column;font-family:var(--devic-cmd-font-family);font-size:var(--devic-cmd-font-size);gap:8px;max-width:100%;width:400px}.devic-command-bar-container[data-position=fixed]{position:fixed}.devic-command-bar-container[data-position=inline]{position:relative}.devic-command-bar-container[data-visible=false]{opacity:0;pointer-events:none;transform:translateY(8px)}.devic-command-bar-container[data-visible=false],.devic-command-bar-container[data-visible=true]{transition:opacity var(--devic-cmd-animation-duration) ease,transform var(--devic-cmd-animation-duration) ease}.devic-command-bar-container[data-visible=true]{opacity:1;transform:translateY(0)}.devic-command-bar{align-items:center;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);display:flex;gap:12px;padding:12px 16px}.devic-command-bar-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:20px;justify-content:center;width:20px}.devic-command-bar-icon svg{height:100%;width:100%}.devic-command-bar-input{background:transparent;border:none;color:inherit;flex:1;font-family:inherit;font-size:inherit;min-width:0;outline:none}.devic-command-bar-input::placeholder{color:var(--devic-cmd-text-secondary)}.devic-command-bar-summary{animation:devic-cmd-pulse 1.5s ease-in-out infinite;color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@keyframes devic-cmd-pulse{0%,to{opacity:1}50%{opacity:.6}}.devic-command-bar-shortcut{background:var(--devic-cmd-border);border-radius:6px;color:var(--devic-cmd-text-secondary);flex-shrink:0;font-size:12px;font-weight:500;letter-spacing:.5px;padding:4px 8px}.devic-command-bar-spinner{animation:devic-cmd-spin .8s linear infinite;border:2px solid var(--devic-cmd-border);border-radius:50%;border-top-color:var(--devic-cmd-primary);height:20px;width:20px}@keyframes devic-cmd-spin{to{transform:rotate(1turn)}}.devic-command-bar-result{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}@keyframes devic-cmd-slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.devic-command-bar-result-tools{border-bottom:1px solid var(--devic-cmd-border)}.devic-command-bar-result-tools-header{align-items:center;color:var(--devic-cmd-text-secondary);cursor:pointer;display:flex;font-size:13px;gap:8px;padding:10px 14px;transition:background .15s ease;user-select:none}.devic-command-bar-result-tools-header:hover{background:rgba(0,0,0,.02)}.devic-command-bar-result-tools-chevron{height:16px;transition:transform .2s ease;width:16px}.devic-command-bar-result-tools-header[data-expanded=true] .devic-command-bar-result-tools-chevron{transform:rotate(90deg)}.devic-command-bar-result-tools-count{align-items:center;background:var(--devic-cmd-primary);border-radius:10px;color:#fff;display:inline-flex;font-size:11px;font-weight:600;height:20px;justify-content:center;min-width:20px;padding:0 6px}.devic-command-bar-result-tools-list{display:flex;flex-direction:column;gap:6px;padding:8px 14px 12px}.devic-command-bar-result-tools-list[data-expanded=false]{display:none}.devic-command-bar-result-tool-item{align-items:center;background:rgba(0,0,0,.02);border-radius:6px;display:flex;font-size:12px;gap:8px;padding:6px 10px}.devic-command-bar-result-tool-icon{color:#10b981;height:14px;width:14px}.devic-command-bar-result-tool-name{color:var(--devic-cmd-text-secondary)}.devic-command-bar-result-message{line-height:1.5;max-height:300px;overflow-y:auto;padding:14px}.devic-command-bar-result-message::-webkit-scrollbar{width:6px}.devic-command-bar-result-message::-webkit-scrollbar-track{background:transparent}.devic-command-bar-result-message::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-error{background:#fef2f2;border:1px solid #fecaca;border-radius:var(--devic-cmd-radius);color:#dc2626;font-size:13px;padding:10px 14px}.devic-command-bar-result-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:14px;text-align:center}.devic-command-bar-dropdown{animation:devic-cmd-slide-up .2s ease-out;background:var(--devic-cmd-bg);border:1px solid var(--devic-cmd-border);border-radius:var(--devic-cmd-radius);box-shadow:var(--devic-cmd-shadow);overflow:hidden}.devic-command-bar-dropdown-header{align-items:center;border-bottom:1px solid var(--devic-cmd-border);color:var(--devic-cmd-text-secondary);display:flex;font-size:12px;font-weight:600;justify-content:space-between;letter-spacing:.5px;padding:10px 14px;text-transform:uppercase}.devic-command-bar-dropdown-hint{align-items:center;display:flex;font-weight:400;gap:4px;letter-spacing:0;text-transform:none}.devic-command-bar-dropdown-hint kbd{align-items:center;background:var(--devic-cmd-border);border-radius:4px;display:inline-flex;font-family:inherit;font-size:10px;height:18px;justify-content:center;min-width:18px;padding:0 4px}.devic-command-bar-dropdown-clear{background:none;border:none;border-radius:4px;color:var(--devic-cmd-primary);cursor:pointer;font-family:inherit;font-size:12px;font-weight:500;letter-spacing:0;padding:2px 6px;text-transform:none}.devic-command-bar-dropdown-clear:hover{background:rgba(0,0,0,.05)}.devic-command-bar-dropdown-list{max-height:250px;overflow-y:auto}.devic-command-bar-dropdown-list::-webkit-scrollbar{width:6px}.devic-command-bar-dropdown-list::-webkit-scrollbar-track{background:transparent}.devic-command-bar-dropdown-list::-webkit-scrollbar-thumb{background:var(--devic-cmd-border);border-radius:3px}.devic-command-bar-dropdown-item{align-items:center;cursor:pointer;display:flex;gap:10px;padding:10px 14px;transition:background .15s ease}.devic-command-bar-dropdown-item:hover,.devic-command-bar-dropdown-item[data-selected=true]{background:rgba(0,0,0,.04)}.devic-command-bar-dropdown-item[data-selected=true]{background:var(--devic-cmd-primary);background:rgba(59,130,246,.1)}.devic-command-bar-dropdown-icon{align-items:center;color:var(--devic-cmd-text-secondary);display:flex;flex-shrink:0;height:16px;justify-content:center;width:16px}.devic-command-bar-dropdown-keyword{color:var(--devic-cmd-text);flex-shrink:0;font-weight:600}.devic-command-bar-dropdown-desc{color:var(--devic-cmd-text-secondary);flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-command-bar-dropdown-empty{color:var(--devic-cmd-text-secondary);font-size:13px;padding:20px 14px;text-align:center}.devic-command-bar-history-item{border-bottom:1px solid rgba(0,0,0,.04)}.devic-command-bar-history-item:last-child{border-bottom:none}.devic-command-bar-history-text{flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-gen-container{--devic-gen-primary:var(--devic-gen-primary-override,#3b82f6);--devic-gen-primary-hover:var(--devic-gen-primary-hover-override,#2563eb);--devic-gen-bg:var(--devic-gen-bg-override,#fff);--devic-gen-text:var(--devic-gen-text-override,#1f2937);--devic-gen-text-secondary:var(--devic-gen-text-secondary-override,#6b7280);--devic-gen-border:var(--devic-gen-border-override,#e5e7eb);--devic-gen-radius:var(--devic-gen-radius-override,8px);--devic-gen-font-family:var(--devic-gen-font-family-override,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif);--devic-gen-font-size:var(--devic-gen-font-size-override,14px);--devic-gen-z-index:var(--devic-gen-z-index-override,10000);--devic-gen-animation-duration:var(--devic-gen-animation-duration-override,200ms);--devic-gen-modal-bg:var(--devic-gen-modal-bg-override,#fff);--devic-gen-modal-text:var(--devic-gen-modal-text-override,#1f2937);--devic-gen-modal-border:var(--devic-gen-modal-border-override,#e5e7eb);font-family:var(--devic-gen-font-family);font-size:var(--devic-gen-font-size)}.devic-gen-button{align-items:center;border:none;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-weight:500;gap:8px;justify-content:center;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-button:disabled{cursor:not-allowed;opacity:.6}.devic-gen-button[data-size=small]{font-size:12px;padding:6px 12px}.devic-gen-button[data-size=medium]{font-size:14px;padding:8px 16px}.devic-gen-button[data-size=large]{font-size:16px;padding:12px 24px}.devic-gen-button[data-variant=primary]{background:var(--devic-gen-primary);color:#fff}.devic-gen-button[data-variant=primary]:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-button[data-variant=secondary]{background:var(--devic-gen-border);color:var(--devic-gen-text)}.devic-gen-button[data-variant=secondary]:hover:not(:disabled){background:#d1d5db}.devic-gen-button[data-variant=outline]{background:transparent;border:1px solid var(--devic-gen-primary);color:var(--devic-gen-primary)}.devic-gen-button[data-variant=outline]:hover:not(:disabled){background:rgba(59,130,246,.1)}.devic-gen-button[data-variant=ghost]{background:transparent;color:var(--devic-gen-text)}.devic-gen-button[data-variant=ghost]:hover:not(:disabled){background:rgba(0,0,0,.05)}.devic-gen-button-icon{align-items:center;display:flex;height:16px;justify-content:center;width:16px}.devic-gen-button-icon svg{height:100%;width:100%}.devic-gen-spinner{animation:devic-gen-spin .8s linear infinite;border:2px solid;border-radius:50%;border-top:2px solid transparent;height:16px;width:16px}.devic-gen-spinner-small{border-width:1.5px;height:12px;width:12px}@keyframes devic-gen-spin{to{transform:rotate(1turn)}}.devic-gen-input{background:var(--devic-gen-modal-bg);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);color:var(--devic-gen-modal-text);font-family:inherit;font-size:inherit;min-height:80px;outline:none;padding:12px;resize:vertical;transition:border-color var(--devic-gen-animation-duration) ease;width:100%}.devic-gen-input:focus{border-color:var(--devic-gen-primary)}.devic-gen-input::placeholder{color:var(--devic-gen-text-secondary)}.devic-gen-error{background:#fef2f2;border:1px solid #fecaca;border-radius:var(--devic-gen-radius);color:#dc2626;font-size:13px;margin-top:8px;padding:8px 12px}.devic-gen-tooltip{animation:devic-gen-fade-in var(--devic-gen-animation-duration) ease-out;background:var(--devic-gen-modal-bg);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);box-shadow:0 4px 20px rgba(0,0,0,.15);padding:12px}@keyframes devic-gen-fade-in{0%{opacity:0;transform:translateY(4px) translateX(-50%)}to{opacity:1;transform:translateY(0) translateX(-50%)}}.devic-gen-tooltip[data-placement=left],.devic-gen-tooltip[data-placement=right]{animation-name:devic-gen-fade-in-horizontal}@keyframes devic-gen-fade-in-horizontal{0%{opacity:0;transform:translateX(4px) translateY(-50%)}to{opacity:1;transform:translateX(0) translateY(-50%)}}.devic-gen-tooltip-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:12px}.devic-gen-tooltip-cancel,.devic-gen-tooltip-confirm{align-items:center;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-tooltip-cancel{background:transparent;border:1px solid var(--devic-gen-modal-border);color:var(--devic-gen-text-secondary)}.devic-gen-tooltip-cancel:hover{background:rgba(0,0,0,.05)}.devic-gen-tooltip-confirm{background:var(--devic-gen-primary);border:none;color:#fff}.devic-gen-tooltip-confirm:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-tooltip-confirm:disabled{cursor:not-allowed;opacity:.6}.devic-gen-modal-overlay{align-items:center;animation:devic-gen-overlay-fade-in var(--devic-gen-animation-duration) ease-out;background:rgba(0,0,0,.5);display:flex;inset:0;justify-content:center;position:fixed;z-index:var(--devic-gen-z-index)}@keyframes devic-gen-overlay-fade-in{0%{opacity:0}to{opacity:1}}.devic-gen-modal{animation:devic-gen-modal-slide-up var(--devic-gen-animation-duration) ease-out;background:var(--devic-gen-modal-bg);border-radius:calc(var(--devic-gen-radius) + 4px);box-shadow:0 20px 50px rgba(0,0,0,.2);margin:16px;max-width:480px;width:100%}@keyframes devic-gen-modal-slide-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.devic-gen-modal-header{align-items:center;border-bottom:1px solid var(--devic-gen-modal-border);display:flex;justify-content:space-between;padding:16px 20px}.devic-gen-modal-title{color:var(--devic-gen-modal-text);font-size:18px;font-weight:600;margin:0}.devic-gen-modal-close{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--devic-gen-text-secondary);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all var(--devic-gen-animation-duration) ease;width:32px}.devic-gen-modal-close:hover{background:rgba(0,0,0,.05);color:var(--devic-gen-modal-text)}.devic-gen-modal-description{color:var(--devic-gen-text-secondary);font-size:14px;line-height:1.5;margin:0;padding:12px 20px 0}.devic-gen-modal-body{padding:16px 20px}.devic-gen-modal-footer{border-top:1px solid var(--devic-gen-modal-border);display:flex;gap:12px;justify-content:flex-end;padding:16px 20px}.devic-gen-modal-cancel,.devic-gen-modal-confirm{align-items:center;border-radius:var(--devic-gen-radius);cursor:pointer;display:inline-flex;font-family:inherit;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all var(--devic-gen-animation-duration) ease}.devic-gen-modal-cancel{background:transparent;border:1px solid var(--devic-gen-modal-border);color:var(--devic-gen-text-secondary)}.devic-gen-modal-cancel:hover{background:rgba(0,0,0,.05);color:var(--devic-gen-modal-text)}.devic-gen-modal-confirm{background:var(--devic-gen-primary);border:none;color:#fff}.devic-gen-modal-confirm:hover:not(:disabled){background:var(--devic-gen-primary-hover)}.devic-gen-modal-confirm:disabled{cursor:not-allowed;opacity:.6}.devic-gen-input::-webkit-scrollbar{width:6px}.devic-gen-input::-webkit-scrollbar-track{background:transparent}.devic-gen-input::-webkit-scrollbar-thumb{background:var(--devic-gen-border);border-radius:3px}.devic-gen-input:disabled{background:var(--devic-gen-border);cursor:not-allowed;opacity:.6}.devic-gen-tool-calls{background:rgba(0,0,0,.02);border:1px solid var(--devic-gen-modal-border);border-radius:var(--devic-gen-radius);display:flex;flex-direction:column;gap:6px;margin-bottom:12px;padding:10px 12px}.devic-gen-tool-item{align-items:center;color:var(--devic-gen-text-secondary);display:flex;font-size:13px;gap:8px}.devic-gen-tool-item[data-status=executing]{color:var(--devic-gen-primary)}.devic-gen-tool-item[data-status=completed] .devic-gen-tool-icon{color:#10b981}.devic-gen-tool-icon{align-items:center;display:flex;flex-shrink:0;height:16px;justify-content:center;width:16px}.devic-gen-tool-icon svg{height:100%;width:100%}.devic-gen-tool-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-gen-tool-custom{padding:8px 0}.devic-gen-processing-status{align-items:center;background:rgba(59,130,246,.05);border:1px solid rgba(59,130,246,.2);border-radius:var(--devic-gen-radius);display:flex;gap:8px;margin-bottom:12px;padding:10px 12px}.devic-gen-processing-text{animation:devic-gen-pulse 1.5s ease-in-out infinite;color:var(--devic-gen-primary);font-size:13px}@keyframes devic-gen-pulse{0%,to{opacity:1}50%{opacity:.6}}.devic-aiwrap-container,.devic-aiwrap-tooltip,.devic-aiwrap-trigger-wrapper{--devic-aiwrap-color:#7c3aed;--devic-aiwrap-color-2:#4f46e5;--devic-aiwrap-bg:#fff;--devic-aiwrap-text:#1f2937;--devic-aiwrap-border:#e5e7eb;--devic-aiwrap-shadow:0 8px 24px rgba(0,0,0,.12)}.devic-aiwrap-container[data-highlight=true] .devic-aiwrap-content{background:rgba(124,58,237,.08);border-radius:4px;outline:1px dashed rgba(124,58,237,.45);outline-offset:2px;transition:background .15s ease,outline-color .15s ease}.devic-aiwrap-content{display:inline;transition:background .15s ease}.devic-aiwrap-trigger-wrapper{display:inline-flex}.devic-aiwrap-trigger{align-items:center;background:linear-gradient(90deg,var(--devic-aiwrap-color) 0,var(--devic-aiwrap-color-2) 100%);border:1px solid hsla(0,0%,100%,.25);box-shadow:0 4px 14px rgba(124,58,237,.35);color:#fff;cursor:pointer;display:inline-flex;font-family:inherit;font-size:13px;font-weight:500;gap:6px;padding:6px 12px;transition:transform .12s ease,box-shadow .12s ease;white-space:nowrap}.devic-aiwrap-trigger:hover{box-shadow:0 6px 18px rgba(124,58,237,.45);transform:translateY(-1px)}.devic-aiwrap-trigger:active{transform:translateY(0)}.devic-aiwrap-trigger-icon{align-items:center;display:inline-flex}.devic-aiwrap-trigger-label{line-height:1}.devic-aiwrap-tooltip{background:var(--devic-aiwrap-bg);border:1px solid var(--devic-aiwrap-border);border-radius:12px;box-shadow:var(--devic-aiwrap-shadow);color:var(--devic-aiwrap-text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;overflow:hidden}.devic-aiwrap-tooltip-header{align-items:center;background:rgba(124,58,237,.05);border-bottom:1px solid var(--devic-aiwrap-border);display:flex;gap:8px;justify-content:space-between;padding:10px 12px}.devic-aiwrap-tooltip-label{color:var(--devic-aiwrap-color);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.devic-aiwrap-tooltip-close{align-items:center;background:transparent;border:none;border-radius:4px;color:#6b7280;cursor:pointer;display:inline-flex;padding:2px}.devic-aiwrap-tooltip-close:hover{background:rgba(0,0,0,.06);color:#111827}.devic-aiwrap-tooltip-body{line-height:1.5;max-height:320px;overflow-y:auto;padding:12px}.devic-aiwrap-processing{align-items:center;color:#6b7280;display:flex;font-size:13px;gap:8px}.devic-aiwrap-spinner{animation:devic-aiwrap-spin .7s linear infinite;border:2px solid rgba(124,58,237,.25);border-radius:50%;border-top:2px solid var(--devic-aiwrap-color);flex-shrink:0;height:14px;width:14px}@keyframes devic-aiwrap-spin{to{transform:rotate(1turn)}}.devic-aiwrap-error{color:#dc2626;font-size:13px}.devic-aiwrap-answer{white-space:pre-wrap;word-break:break-word}
@@ -20,6 +20,7 @@ const DEFAULT_OPTIONS = {
20
20
  maxFileSize: 10 * 1024 * 1024,
21
21
  enableSpeechToText: false,
22
22
  speechLanguage: undefined,
23
+ speechAutoStop: true,
23
24
  inputPlaceholder: 'Type a message...',
24
25
  title: 'Chat',
25
26
  showAvatar: false,
@@ -388,7 +389,7 @@ function ChatDrawerInner({ assistantId, chatUid: initialChatUid, options = {}, e
388
389
  references,
389
390
  removeReference,
390
391
  clearReferences,
391
- }) })) : (jsx(ChatInput, { onSend: handleSend, disabled: chat.isLoading || chat.handedOff || inlineWidgets.length > 0, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize, enableSpeechToText: mergedOptions.enableSpeechToText, speechLanguage: mergedOptions.speechLanguage, speechTenantId: tenantId, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, sendButtonContent: mergedOptions.sendButtonContent, disabledMessage: chat.handedOff
392
+ }) })) : (jsx(ChatInput, { onSend: handleSend, disabled: chat.isLoading || chat.handedOff || inlineWidgets.length > 0, placeholder: mergedOptions.inputPlaceholder, enableFileUploads: mergedOptions.enableFileUploads, allowedFileTypes: mergedOptions.allowedFileTypes, maxFileSize: mergedOptions.maxFileSize, enableSpeechToText: mergedOptions.enableSpeechToText, speechLanguage: mergedOptions.speechLanguage, speechTenantId: tenantId, speechAutoStop: mergedOptions.speechAutoStop, apiKey: resolvedApiKey, baseUrl: resolvedBaseUrl, sendButtonContent: mergedOptions.sendButtonContent, disabledMessage: chat.handedOff
392
393
  ? 'Waiting for subagent to complete'
393
394
  : inlineWidgets.length > 0
394
395
  ? 'Waiting for tool response'