@alexkroman1/aai-ui 5.10.1 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/_colors-CcAi2FOU.js +44 -0
  2. package/dist/{chat-view-DFBmX5eX.js → chat-view-DadZOvJO.js} +11 -7
  3. package/dist/client-config.d.ts +29 -0
  4. package/dist/components/_colors.d.ts +35 -9
  5. package/dist/components/button.js +31 -15
  6. package/dist/components/chat-view.js +1 -1
  7. package/dist/components/controls.js +1 -1
  8. package/dist/components/message-list.js +1 -1
  9. package/dist/components/sidebar-layout.js +9 -8
  10. package/dist/components/start-screen.js +2 -2
  11. package/dist/components/tool-call-block.js +1 -1
  12. package/dist/{controls-CoBO6sId.js → controls-DzQEKq9c.js} +8 -7
  13. package/dist/default-client/assets/{audio-DJF-gC7e.js → audio-Dwj4W2wx.js} +1 -1
  14. package/dist/default-client/assets/{capture-processor-D_A9RUeB.js → capture-processor-wdpgNZAH.js} +1 -1
  15. package/dist/default-client/assets/index-Ctjrde3-.css +2 -0
  16. package/dist/default-client/assets/index-DuE6Ab-l.js +278 -0
  17. package/dist/default-client/assets/{playback-processor-GPTQTyza.js → playback-processor-D_5OVt9F.js} +1 -1
  18. package/dist/default-client/index.html +2 -2
  19. package/dist/define-client.js +3 -3
  20. package/dist/index.js +5 -5
  21. package/dist/{message-list-DkAHoB3A.js → message-list-YdLocGoT.js} +11 -9
  22. package/dist/{session-core-CS37WE1G.js → session-core-OfnXNMuL.js} +182 -39
  23. package/dist/session-core-handshake.d.ts +25 -0
  24. package/dist/session-core-reconnect.d.ts +8 -0
  25. package/dist/session-core.js +1 -1
  26. package/dist/{tool-call-block-BjemDFB9.js → tool-call-block-CAscLGFy.js} +6 -6
  27. package/package.json +2 -2
  28. package/dist/_colors-Bfh3-BVE.js +0 -29
  29. package/dist/default-client/assets/index-1JIz81CD.css +0 -2
  30. package/dist/default-client/assets/index-D_RNiTIh.js +0 -278
@@ -0,0 +1,44 @@
1
+ //#region components/_colors.ts
2
+ /**
3
+ * Shared tints used by the default components (AssemblyAI design system,
4
+ * "website refresh": warm neutrals over the cream/white surfaces).
5
+ *
6
+ * These sit on top of the {@link ClientTheme} colors, which own the opaque
7
+ * palette. The neutral text steps are **derived from the theme** rather than
8
+ * hardcoded: `ClientTheme` documents `bg`/`surface`/`text` as free-form
9
+ * colors, so a client is free to hand the components a dark ground — and a
10
+ * fixed warm-grey scale tuned for cream leaves the AGENT/TOOL labels, every
11
+ * tool-call args preview, the chevron and both URL chips below WCAG AA while
12
+ * the prose and bubbles around them follow the theme correctly. Measured on a
13
+ * plausible dark theme before this was derived: 14 text nodes under 4.5:1
14
+ * (the faint step at 3.2–3.5:1, the muted step at 2.5:1), against zero on the
15
+ * default light theme.
16
+ *
17
+ * `ERROR_COLOR` and `THINKING_COLOR` stay fixed: they are *semantic* colors
18
+ * whose hue carries the meaning, so they cannot be re-derived from a theme
19
+ * that knows nothing about severity.
20
+ */
21
+ /**
22
+ * Blend `text` into `surface` by `pct`, giving a neutral step that stays on
23
+ * the theme's own ink/ground axis. On a light theme this walks *down* from
24
+ * the surface toward the ink; on a dark one it walks *up* from the ground
25
+ * toward the light ink — the same call reads correctly either way, which is
26
+ * the whole reason to derive rather than hardcode.
27
+ */
28
+ function inkTint(text, surface, pct) {
29
+ return `color-mix(in srgb, ${text} ${pct}%, ${surface})`;
30
+ }
31
+ /** Error red tuned for warm light surfaces. */
32
+ const ERROR_COLOR = "#B3261E";
33
+ /** Amber used by the "thinking" state indicator. */
34
+ const THINKING_COLOR = "#B98900";
35
+ /**
36
+ * Derive the user-bubble fill/edge from the theme primary (the mock's
37
+ * indigo-50 background with an indigo-100 border), so custom themes keep a
38
+ * coherent tinted bubble instead of a hardcoded indigo.
39
+ */
40
+ function primaryTint(primary, surface, pct) {
41
+ return `color-mix(in srgb, ${primary} ${pct}%, ${surface})`;
42
+ }
43
+ //#endregion
44
+ export { primaryTint as i, THINKING_COLOR as n, inkTint as r, ERROR_COLOR as t };
@@ -1,26 +1,30 @@
1
1
  import { useSessionSelector, useTheme } from "./context.js";
2
- import { a as THINKING_COLOR, r as TEXT_FAINT, t as ERROR_COLOR } from "./_colors-Bfh3-BVE.js";
2
+ import { n as THINKING_COLOR, r as inkTint, t as ERROR_COLOR } from "./_colors-CcAi2FOU.js";
3
3
  import { t as AaiLogo } from "./aai-logo-B8lDmsut.js";
4
4
  import { t as Eyebrow } from "./eyebrow-C6ZFuiz6.js";
5
- import { t as Controls } from "./controls-CoBO6sId.js";
6
- import { t as MessageList } from "./message-list-DkAHoB3A.js";
5
+ import { t as Controls } from "./controls-DzQEKq9c.js";
6
+ import { t as MessageList } from "./message-list-YdLocGoT.js";
7
7
  import clsx from "clsx";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region components/console-shell.tsx
10
10
  /** @jsxImportSource react */
11
11
  /**
12
- * Indicator dot color per state, on the light refresh palette.
12
+ * Indicator dot color per state.
13
+ *
14
+ * `idle` is the theme's own faint ink step rather than a fixed warm grey, so
15
+ * the dot stays visible on a dark ground; the thinking amber and error red
16
+ * are semantic and stay fixed.
13
17
  *
14
18
  * @internal
15
19
  */
16
- function stateColor(state, primary) {
20
+ function stateColor(state, primary, idle) {
17
21
  switch (state) {
18
22
  case "listening":
19
23
  case "speaking":
20
24
  case "ready": return primary;
21
25
  case "thinking": return THINKING_COLOR;
22
26
  case "error": return ERROR_COLOR;
23
- default: return TEXT_FAINT;
27
+ default: return idle;
24
28
  }
25
29
  }
26
30
  /**
@@ -56,7 +60,7 @@ function ConsoleShell({ icon, title, state, pulsing, error, children, footer, cl
56
60
  children: [/* @__PURE__ */ jsx("span", {
57
61
  className: "w-[7px] h-[7px] rounded-full",
58
62
  style: {
59
- background: stateColor(state, theme.primary),
63
+ background: stateColor(state, theme.primary, inkTint(theme.text, theme.bg, 65)),
60
64
  animation: pulsing ? "aai-pulse 1.6s ease-in-out infinite" : "none"
61
65
  }
62
66
  }), state]
@@ -21,6 +21,35 @@ export type { ClientConfigResponse } from "@alexkroman1/aai/protocol";
21
21
  * @internal
22
22
  */
23
23
  export declare function buildAgentUrl(platformUrl: string, endpointPath: string): URL;
24
+ /**
25
+ * Per-attempt deadline for the `client-config` lookup.
26
+ *
27
+ * A request issued while the platform is restarting or saturated can HANG
28
+ * rather than fail — the proxy holds the socket open — and a browser fetch
29
+ * has no timeout of its own. Every other failure here is already handled
30
+ * (`null`, then the same-origin fallback), but a hang is not a failure: the
31
+ * promise simply never settles.
32
+ *
33
+ * That is unrecoverable rather than merely slow, because this lookup runs
34
+ * inside the session's WebSocket URL *provider*. partysocket awaits the
35
+ * provider under `_connectLock` and arms its own `connectionTimeout` only
36
+ * AFTER the URL resolves, so a hung lookup means no socket is ever
37
+ * constructed, no `error`/`close` ever fires, and none of the 10 reconnect
38
+ * attempts ever happen — the session sits on "connecting" forever, and stays
39
+ * there long after the server is back. Reproduced: zero sockets opened.
40
+ *
41
+ * A timed-out attempt therefore degrades exactly like any other failed one —
42
+ * `null`, so `serverIsBroker` stays unlatched and the attempt falls through
43
+ * to the same-origin `websocket` path, whose failure re-enters the normal
44
+ * backoff and re-fetches this on the next attempt.
45
+ *
46
+ * Sized well above the real work (one same-origin JSON GET that reads the
47
+ * agent's row) and well under a user's patience — the same 10s the studio's
48
+ * gating reads use for the identical hazard.
49
+ *
50
+ * @internal
51
+ */
52
+ export declare const CLIENT_CONFIG_ATTEMPT_TIMEOUT_MS = 10000;
24
53
  /**
25
54
  * Fetch the agent's client config, reporting `null` when the lookup did not
26
55
  * produce an answer (network error, non-2xx, unparsable body).
@@ -2,16 +2,42 @@
2
2
  * Shared tints used by the default components (AssemblyAI design system,
3
3
  * "website refresh": warm neutrals over the cream/white surfaces).
4
4
  *
5
- * These sit on top of the {@link ClientTheme} colors (which own the opaque
6
- * palette) and are intentionally not themeable: they are the warm-gray text
7
- * steps and ink alpha layers the refresh uses over any light surface.
5
+ * These sit on top of the {@link ClientTheme} colors, which own the opaque
6
+ * palette. The neutral text steps are **derived from the theme** rather than
7
+ * hardcoded: `ClientTheme` documents `bg`/`surface`/`text` as free-form
8
+ * colors, so a client is free to hand the components a dark ground — and a
9
+ * fixed warm-grey scale tuned for cream leaves the AGENT/TOOL labels, every
10
+ * tool-call args preview, the chevron and both URL chips below WCAG AA while
11
+ * the prose and bubbles around them follow the theme correctly. Measured on a
12
+ * plausible dark theme before this was derived: 14 text nodes under 4.5:1
13
+ * (the faint step at 3.2–3.5:1, the muted step at 2.5:1), against zero on the
14
+ * default light theme.
15
+ *
16
+ * `ERROR_COLOR` and `THINKING_COLOR` stay fixed: they are *semantic* colors
17
+ * whose hue carries the meaning, so they cannot be re-derived from a theme
18
+ * that knows nothing about severity.
19
+ */
20
+ /**
21
+ * Blend `text` into `surface` by `pct`, giving a neutral step that stays on
22
+ * the theme's own ink/ground axis. On a light theme this walks *down* from
23
+ * the surface toward the ink; on a dark one it walks *up* from the ground
24
+ * toward the light ink — the same call reads correctly either way, which is
25
+ * the whole reason to derive rather than hardcode.
26
+ */
27
+ export declare function inkTint(text: string, surface: string, pct: number): string;
28
+ /**
29
+ * Muted text — subtitles, secondary labels, thinking dots (fg-muted).
30
+ * 75% lands within a couple of RGB steps of the design system's `#57534B`
31
+ * on the default theme.
32
+ */
33
+ export declare const INK_MUTED_PCT = 75;
34
+ /**
35
+ * Faint text — live transcripts, state indicator, start-screen subtitle.
36
+ * 65% reproduces the design system's `#6F6A60` on the default theme.
8
37
  */
9
- /** Muted text subtitles, secondary labels, thinking dots (fg-muted). */
10
- export declare const TEXT_MUTED = "#57534B";
11
- /** Faint text live transcripts, state indicator, start-screen subtitle (warm-500). */
12
- export declare const TEXT_FAINT = "#6F6A60";
13
- /** Subtle surface tint — message bubbles, tool-call blocks. */
14
- export declare const SURFACE_TINT = "rgba(20,18,12,0.03)";
38
+ export declare const INK_FAINT_PCT = 65;
39
+ /** Subtle surface tint inline code, tool-call chips, message bubbles. */
40
+ export declare const INK_SURFACE_PCT = 3;
15
41
  /** Error red tuned for warm light surfaces. */
16
42
  export declare const ERROR_COLOR = "#B3261E";
17
43
  /** Amber used by the "thinking" state indicator. */
@@ -1,4 +1,5 @@
1
1
  import { useTheme } from "../context.js";
2
+ import { i as primaryTint, r as inkTint } from "../_colors-CcAi2FOU.js";
2
3
  import clsx from "clsx";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  //#region components/button.tsx
@@ -32,29 +33,44 @@ import { jsx } from "react/jsx-runtime";
32
33
  */
33
34
  function Button({ variant = "default", size = "default", className, children, style, ...rest }) {
34
35
  const theme = useTheme();
35
- let variantStyle;
36
- if (variant === "default") variantStyle = {
37
- background: theme.primary,
38
- color: theme.surface,
39
- borderColor: "transparent"
36
+ let colors;
37
+ if (variant === "default") colors = {
38
+ bg: theme.primary,
39
+ fg: theme.surface,
40
+ border: "transparent",
41
+ hoverBg: inkTint(theme.text, theme.primary, 14),
42
+ hoverFg: theme.surface,
43
+ hoverBorder: "transparent"
40
44
  };
41
- else if (variant === "secondary") variantStyle = {
42
- background: "transparent",
43
- color: theme.primary,
44
- borderColor: theme.primary
45
+ else if (variant === "secondary") colors = {
46
+ bg: "transparent",
47
+ fg: theme.primary,
48
+ border: theme.primary,
49
+ hoverBg: primaryTint(theme.primary, theme.surface, 8),
50
+ hoverFg: theme.primary,
51
+ hoverBorder: theme.primary
45
52
  };
46
- else variantStyle = {
47
- background: theme.surface,
48
- color: theme.text,
49
- borderColor: theme.border
53
+ else colors = {
54
+ bg: theme.surface,
55
+ fg: theme.text,
56
+ border: theme.border,
57
+ hoverBg: inkTint(theme.text, theme.surface, 5),
58
+ hoverFg: theme.text,
59
+ hoverBorder: theme.border
50
60
  };
51
61
  return /* @__PURE__ */ jsx("button", {
52
62
  type: "button",
53
63
  style: {
54
- ...variantStyle,
64
+ "--aai-btn-bg": colors.bg,
65
+ "--aai-btn-fg": colors.fg,
66
+ "--aai-btn-bd": colors.border,
67
+ "--aai-btn-bg-hover": colors.hoverBg,
68
+ "--aai-btn-fg-hover": colors.hoverFg,
69
+ "--aai-btn-bd-hover": colors.hoverBorder,
70
+ outlineColor: theme.primary,
55
71
  ...style
56
72
  },
57
- className: clsx("inline-flex items-center justify-center appearance-none m-0 w-fit whitespace-nowrap", size === "lg" ? "h-11 px-7 text-xs" : "h-9 px-5 text-[11px]", "rounded-aai font-aai font-medium tracking-[1.4px] uppercase leading-none", "cursor-pointer border outline-none transition-colors duration-150", "disabled:cursor-not-allowed disabled:opacity-50", className),
73
+ className: clsx("inline-flex items-center justify-center appearance-none m-0 w-fit whitespace-nowrap", size === "lg" ? "h-11 px-7 text-xs" : "h-9 px-5 text-[11px]", "rounded-aai font-aai font-medium tracking-[1.4px] uppercase leading-none", "cursor-pointer border transition-colors duration-150", "bg-(--aai-btn-bg) text-(--aai-btn-fg) border-(--aai-btn-bd)", "enabled:hover:bg-(--aai-btn-bg-hover) enabled:hover:text-(--aai-btn-fg-hover)", "enabled:hover:border-(--aai-btn-bd-hover)", "outline-none focus-visible:[outline:2px_solid] focus-visible:[outline-offset:2px]", "disabled:cursor-not-allowed disabled:opacity-50", className),
58
74
  ...rest,
59
75
  children
60
76
  });
@@ -1,3 +1,3 @@
1
1
  import "../context.js";
2
- import { t as ChatView } from "../chat-view-DFBmX5eX.js";
2
+ import { t as ChatView } from "../chat-view-DadZOvJO.js";
3
3
  export { ChatView };
@@ -1,3 +1,3 @@
1
1
  import "../context.js";
2
- import { t as Controls } from "../controls-CoBO6sId.js";
2
+ import { t as Controls } from "../controls-DzQEKq9c.js";
3
3
  export { Controls };
@@ -1,3 +1,3 @@
1
1
  import "../context.js";
2
- import { t as MessageList } from "../message-list-DkAHoB3A.js";
2
+ import { t as MessageList } from "../message-list-YdLocGoT.js";
3
3
  export { MessageList };
@@ -29,20 +29,21 @@ import { jsx, jsxs } from "react/jsx-runtime";
29
29
  function SidebarLayout({ sidebar, children, sidebarWidth = "18rem", sidebarPosition = "left", className }) {
30
30
  const theme = useTheme();
31
31
  const sidebarEl = /* @__PURE__ */ jsx("div", {
32
- className: "shrink-0 flex flex-col overflow-y-auto",
33
- style: {
34
- width: sidebarWidth,
35
- ...sidebarPosition === "left" ? { borderRight: `1px solid ${theme.border}` } : { borderLeft: `1px solid ${theme.border}` }
36
- },
32
+ className: clsx("shrink-0 flex flex-col overflow-y-auto", "w-full max-h-[40vh] md:w-(--aai-sidebar-w) md:max-h-none", sidebarPosition === "left" ? "border-b md:border-b-0 md:border-r" : "border-t md:border-t-0 md:border-l order-last md:order-none"),
33
+ style: { borderColor: theme.border },
37
34
  children: sidebar
38
35
  });
36
+ const vars = {
37
+ background: theme.bg,
38
+ "--aai-sidebar-w": sidebarWidth
39
+ };
39
40
  return /* @__PURE__ */ jsxs("div", {
40
- className: clsx("flex h-screen", className),
41
- style: { background: theme.bg },
41
+ className: clsx("flex flex-col md:flex-row min-h-screen md:h-screen", className),
42
+ style: vars,
42
43
  children: [
43
44
  sidebarPosition === "left" && sidebarEl,
44
45
  /* @__PURE__ */ jsx("div", {
45
- className: "flex-1 min-w-0",
46
+ className: "flex-1 min-w-0 min-h-0",
46
47
  children
47
48
  }),
48
49
  sidebarPosition === "right" && sidebarEl
@@ -1,6 +1,6 @@
1
1
  import { useSessionCore, useSessionSelector, useTheme } from "../context.js";
2
+ import { r as inkTint } from "../_colors-CcAi2FOU.js";
2
3
  import { Button } from "./button.js";
3
- import "../_colors-Bfh3-BVE.js";
4
4
  import { t as AaiLogo } from "../aai-logo-B8lDmsut.js";
5
5
  import { t as Eyebrow } from "../eyebrow-C6ZFuiz6.js";
6
6
  import clsx from "clsx";
@@ -52,7 +52,7 @@ function StartScreen({ children, icon, title, subtitle, buttonText = "Start Conv
52
52
  }),
53
53
  subtitle && /* @__PURE__ */ jsx("p", {
54
54
  className: "text-[15px] leading-[22px] m-0 max-w-75",
55
- style: { color: "#57534B" },
55
+ style: { color: inkTint(theme.text, theme.surface, 75) },
56
56
  children: subtitle
57
57
  }),
58
58
  /* @__PURE__ */ jsx(Button, {
@@ -1,3 +1,3 @@
1
1
  import "../context.js";
2
- import { t as ToolCallBlock } from "../tool-call-block-BjemDFB9.js";
2
+ import { t as ToolCallBlock } from "../tool-call-block-CAscLGFy.js";
3
3
  export { ToolCallBlock };
@@ -1,6 +1,6 @@
1
1
  import { useSessionCore, useSessionSelector, useTheme } from "./context.js";
2
+ import { r as inkTint } from "./_colors-CcAi2FOU.js";
2
3
  import { Button } from "./components/button.js";
3
- import { i as TEXT_MUTED, n as SURFACE_TINT, r as TEXT_FAINT } from "./_colors-Bfh3-BVE.js";
4
4
  import { t as pageBaseUrl } from "./_utils-CsqbIVGI.js";
5
5
  import clsx from "clsx";
6
6
  import { memo, useEffect, useRef, useState } from "react";
@@ -33,16 +33,17 @@ function UrlChip({ label, url, hint, testId, className }) {
33
33
  type: "button",
34
34
  onClick: copy,
35
35
  title: `${hint} (click to copy)\n${url}`,
36
- className: clsx("flex items-center gap-1.5 min-w-0 appearance-none m-0 px-2 py-1 rounded-aai border cursor-pointer outline-none text-[11px] leading-none font-aai-mono", className),
36
+ className: clsx("flex items-center gap-1.5 min-w-0 appearance-none m-0 px-2 py-1 rounded-aai border cursor-pointer text-[11px] leading-none font-aai-mono", "outline-none focus-visible:[outline:2px_solid] focus-visible:[outline-offset:2px]", className),
37
37
  style: {
38
- background: SURFACE_TINT,
38
+ background: inkTint(theme.text, theme.surface, 3),
39
39
  borderColor: theme.border,
40
- color: TEXT_FAINT
40
+ color: inkTint(theme.text, theme.surface, 65),
41
+ outlineColor: theme.primary
41
42
  },
42
43
  "data-testid": testId,
43
44
  children: [/* @__PURE__ */ jsx("span", {
44
45
  className: "uppercase tracking-wide shrink-0",
45
- style: { color: TEXT_MUTED },
46
+ style: { color: inkTint(theme.text, theme.surface, 75) },
46
47
  children: copied ? "Copied" : label
47
48
  }), /* @__PURE__ */ jsx("span", {
48
49
  className: "truncate",
@@ -121,7 +122,7 @@ const Controls = memo(function Controls({ className }) {
121
122
  const running = useSessionSelector((s) => s.running);
122
123
  const { toggle, reset } = useSessionCore();
123
124
  return /* @__PURE__ */ jsxs("div", {
124
- className: clsx("flex items-center gap-3 shrink-0", className),
125
+ className: clsx("flex flex-wrap items-center gap-3 shrink-0", className),
125
126
  children: [
126
127
  /* @__PURE__ */ jsx(Button, {
127
128
  variant: "secondary",
@@ -133,7 +134,7 @@ const Controls = memo(function Controls({ className }) {
133
134
  onClick: reset,
134
135
  children: "New Conversation"
135
136
  }),
136
- /* @__PURE__ */ jsx(SessionUrlChips, { className: "ml-auto max-w-[60%]" })
137
+ /* @__PURE__ */ jsx(SessionUrlChips, { className: "basis-full sm:basis-auto sm:ml-auto sm:max-w-[60%]" })
137
138
  ]
138
139
  });
139
140
  });
@@ -1 +1 @@
1
- import{a as e,o as t,t as n}from"./index-D_RNiTIh.js";function r(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function i(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function a(e,t,n){let r=new AudioWorkletNode(e,`capture-processor`,{channelCount:1,channelCountMode:`explicit`}),i=null;return r.port.onmessage=e=>{let r=e.data;r.event===`chunk`&&r.buffer?t(r.buffer):r.event===`silent`?n?.():r.event===`stopped`&&(i?.(),i=null)},{node:r,start(){r.port.postMessage({event:`start`})},stop(){return new Promise(e=>{let t=setTimeout(e,250);i=()=>{clearTimeout(t),e()},r.port.postMessage({event:`stop`})})}}}async function o(o){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:d,onError:f,onPlaybackStats:p,onPlaybackProgress:m,onMicSilent:h}=o,g=new AudioContext({sampleRate:c,latencyHint:`playback`}),_=s===c,v=_?g:new AudioContext({sampleRate:s,latencyHint:`interactive`});async function y(){let e=_?[g]:[g,v];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let b=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...n}}),x;try{[x]=await Promise.all([b,g.resume(),v.resume(),v.audioWorklet.addModule(l),g.audioWorklet.addModule(u)]),r(v.sampleRate,s,`capture`),r(g.sampleRate,c,`playback`)}catch(e){throw i(b),await y(),e}let S=v.createMediaStreamSource(x),C=a(v,d,h);S.connect(C.node),C.node.onprocessorerror=()=>{let e=Error(`Audio capture worklet crashed`);console.error(`[aai-ui]`,e.message),f?.(e)},C.start();let w=null,T=null,E=0,D=null,O=new AbortController;function k(){T?.(),T=null,D=null}function A(e){e.stats&&e.stats.concealedSamples>0&&p?.(e.stats),e.reason!==`interrupt`&&(D!==null&&e.turn!==D||k())}function j(){if(w)return w;let e=new AudioWorkletNode(g,`playback-processor`);return e.connect(g.destination),e.port.onmessage=e=>{e.data.event===`stop`?A(e.data):e.data.event===`progress`&&m?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=Error(`Audio playback worklet crashed`);console.error(`[aai-ui]`,e.message),k(),f?.(e)},w=e,e}let M={enqueue(e){O.signal.aborted||e.byteLength!==0&&j().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!w)return Promise.resolve();let n=++E;return w.port.postMessage({event:`done`,turn:n}),g.state===`running`?new Promise(r=>{T?.();let i=()=>{clearInterval(a),clearTimeout(o),T===i&&(T=null,D=null),r()},a=setInterval(()=>{g.state!==`running`&&i()},t),o=setTimeout(i,e);T=i,D=n}):(D=null,Promise.resolve())},flush(){w&&(k(),w.port.postMessage({event:`interrupt`}))},async close(){if(!O.signal.aborted){O.abort(),await C.stop(),S.disconnect(),C.node.disconnect(),w&&w.disconnect();for(let e of x.getTracks())e.stop();await y()}},async[Symbol.asyncDispose](){await M.close()}};return M}export{o as createVoiceIO};
1
+ import{a as e,o as t,t as n}from"./index-DuE6Ab-l.js";function r(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function i(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function a(e,t,n){let r=new AudioWorkletNode(e,`capture-processor`,{channelCount:1,channelCountMode:`explicit`}),i=null;return r.port.onmessage=e=>{let r=e.data;r.event===`chunk`&&r.buffer?t(r.buffer):r.event===`silent`?n?.():r.event===`stopped`&&(i?.(),i=null)},{node:r,start(){r.port.postMessage({event:`start`})},stop(){return new Promise(e=>{let t=setTimeout(e,250);i=()=>{clearTimeout(t),e()},r.port.postMessage({event:`stop`})})}}}async function o(o){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:d,onError:f,onPlaybackStats:p,onPlaybackProgress:m,onMicSilent:h}=o,g=new AudioContext({sampleRate:c,latencyHint:`playback`}),_=s===c,v=_?g:new AudioContext({sampleRate:s,latencyHint:`interactive`});async function y(){let e=_?[g]:[g,v];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let b=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...n}}),x;try{[x]=await Promise.all([b,g.resume(),v.resume(),v.audioWorklet.addModule(l),g.audioWorklet.addModule(u)]),r(v.sampleRate,s,`capture`),r(g.sampleRate,c,`playback`)}catch(e){throw i(b),await y(),e}let S=v.createMediaStreamSource(x),C=a(v,d,h);S.connect(C.node),C.node.onprocessorerror=()=>{let e=Error(`Audio capture worklet crashed`);console.error(`[aai-ui]`,e.message),f?.(e)},C.start();let w=null,T=null,E=0,D=null,O=new AbortController;function k(){T?.(),T=null,D=null}function A(e){e.stats&&e.stats.concealedSamples>0&&p?.(e.stats),e.reason!==`interrupt`&&(D!==null&&e.turn!==D||k())}function j(){if(w)return w;let e=new AudioWorkletNode(g,`playback-processor`);return e.connect(g.destination),e.port.onmessage=e=>{e.data.event===`stop`?A(e.data):e.data.event===`progress`&&m?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=Error(`Audio playback worklet crashed`);console.error(`[aai-ui]`,e.message),k(),f?.(e)},w=e,e}let M={enqueue(e){O.signal.aborted||e.byteLength!==0&&j().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!w)return Promise.resolve();let n=++E;return w.port.postMessage({event:`done`,turn:n}),g.state===`running`?new Promise(r=>{T?.();let i=()=>{clearInterval(a),clearTimeout(o),T===i&&(T=null,D=null),r()},a=setInterval(()=>{g.state!==`running`&&i()},t),o=setTimeout(i,e);T=i,D=n}):(D=null,Promise.resolve())},flush(){w&&(k(),w.port.postMessage({event:`interrupt`}))},async close(){if(!O.signal.aborted){O.abort(),await C.stop(),S.disconnect(),C.node.disconnect(),w&&w.disconnect();for(let e of x.getTracks())e.stop();await y()}},async[Symbol.asyncDispose](){await M.close()}};return M}export{o as createVoiceIO};
@@ -1,4 +1,4 @@
1
- import{n as e,r as t}from"./index-D_RNiTIh.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=n(`
1
+ import{n as e,r as t}from"./index-DuE6Ab-l.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=n(`
2
2
  class CaptureProcessor extends AudioWorkletProcessor {
3
3
  constructor(options) {
4
4
  super();
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--font-aai:"Monument Grotesk", "ABC Monument Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-aai-serif:"Source Serif 4", "Source Serif Pro", Charter, "Iowan Old Style", Georgia, serif;--font-aai-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;--radius-aai:4px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}html,body{margin:0;padding:0}}@layer components;@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.order-last{order:9999}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-auto{margin-inline:auto}.my-0\.5{margin-block:calc(var(--spacing) * .5)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2\.5{margin-block:calc(var(--spacing) * 2.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.box-border{box-sizing:border-box}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-4{height:calc(var(--spacing) * 4)}.h-9{height:calc(var(--spacing) * 9)}.h-11{height:calc(var(--spacing) * 11)}.h-\[7px\]{height:7px}.h-screen{height:100vh}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[40vh\]{max-height:40vh}.min-h-0{min-height:0}.min-h-5{min-height:calc(var(--spacing) * 5)}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-4{width:calc(var(--spacing) * 4)}.w-\[7px\]{width:7px}.w-fit{width:fit-content}.w-full{width:100%}.max-w-75{max-width:calc(var(--spacing) * 75)}.max-w-105{max-width:calc(var(--spacing) * 105)}.max-w-190{max-width:calc(var(--spacing) * 190)}.max-w-\[82\%\]{max-width:82%}.max-w-\[min\(78\%\,64ch\)\]{max-width:min(78%,64ch)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.rotate-90{rotate:90deg}.cursor-pointer{cursor:pointer}.resize{resize:both}.\[scrollbar-width\:none\]{scrollbar-width:none}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded-aai{border-radius:var(--radius-aai)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-none{--tw-border-style:none;border-style:none}.border-\(--aai-btn-bd\){border-color:var(--aai-btn-bd)}.bg-\(--aai-btn-bg\){background-color:var(--aai-btn-bg)}.bg-transparent{background-color:#0000}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-7{padding:calc(var(--spacing) * 7)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-10{padding-inline:calc(var(--spacing) * 10)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.font-aai{font-family:var(--font-aai)}.font-aai-mono{font-family:var(--font-aai-mono)}.font-aai-serif{font-family:var(--font-aai-serif)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[22px\]{font-size:22px}.text-\[32px\]{font-size:32px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-\[1\.15\]{--tw-leading:1.15;line-height:1.15}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[23px\]{--tw-leading:23px;line-height:23px}.leading-\[130\%\]{--tw-leading:130%;line-height:130%}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.2px\]{--tw-tracking:-.2px;letter-spacing:-.2px}.tracking-\[1\.2px\]{--tw-tracking:1.2px;letter-spacing:1.2px}.tracking-\[1\.4px\]{--tw-tracking:1.4px;letter-spacing:1.4px}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-balance{text-wrap:balance}.wrap-break-word{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\(--aai-btn-fg\){color:var(--aai-btn-fg)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.first\:mt-0:first-child{margin-top:0}.last\:mb-0:last-child{margin-bottom:0}.focus-visible\:\[outline\:2px_solid\]:focus-visible{outline:2px solid}.focus-visible\:\[outline-offset\:2px\]:focus-visible{outline-offset:2px}@media (hover:hover){.enabled\:hover\:border-\(--aai-btn-bd-hover\):enabled:hover{border-color:var(--aai-btn-bd-hover)}.enabled\:hover\:bg-\(--aai-btn-bg-hover\):enabled:hover{background-color:var(--aai-btn-bg-hover)}.enabled\:hover\:text-\(--aai-btn-fg-hover\):enabled:hover{color:var(--aai-btn-fg-hover)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\:ml-auto{margin-left:auto}.sm\:max-w-\[60\%\]{max-width:60%}.sm\:basis-auto{flex-basis:auto}.sm\:px-16{padding-inline:calc(var(--spacing) * 16)}.sm\:py-14{padding-block:calc(var(--spacing) * 14)}}@media (width>=48rem){.md\:order-none{order:0}.md\:h-screen{height:100vh}.md\:max-h-none{max-height:none}.md\:w-\(--aai-sidebar-w\){width:var(--aai-sidebar-w)}.md\:flex-row{flex-direction:row}.md\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.md\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.md\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.md\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}}}@keyframes aai-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}@keyframes aai-bounce{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}@keyframes aai-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.tool-shimmer{-webkit-text-fill-color:transparent;background:linear-gradient(90deg,currentColor 25%,#0000 50%,currentColor 75%) 0 0/200% 100%;-webkit-background-clip:text;background-clip:text;animation:2s infinite aai-shimmer}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}