@frankieai/react 0.2.19 → 0.2.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
+ ActionConfirm: () => ActionConfirm,
24
25
  Avatar: () => Avatar,
25
26
  Badge: () => Badge,
26
27
  Button: () => Button,
@@ -124,6 +125,8 @@ var FrankieClient = class {
124
125
  session;
125
126
  /** Identity (JWT `sub`, else the raw token) the cached session was issued for. */
126
127
  sessionUserKey;
128
+ /** The host token fetched for the latest turn; sent with it so tools get a live one. */
129
+ latestUserToken;
127
130
  get sessionId() {
128
131
  return this.session?.sessionId;
129
132
  }
@@ -185,6 +188,7 @@ var FrankieClient = class {
185
188
  "user_token_unavailable"
186
189
  );
187
190
  }
191
+ this.latestUserToken = userToken;
188
192
  const userKey = sessionIdentity(userToken);
189
193
  if (userKey !== this.sessionUserKey) this.resetSession();
190
194
  if (this.session && new Date(this.session.expiresAt).getTime() > Date.now() + 3e4) return this.session;
@@ -277,7 +281,11 @@ var FrankieClient = class {
277
281
  message: input.message,
278
282
  ...input.context ? { context: input.context } : {},
279
283
  ...input.model ? { model: input.model } : {},
280
- ...input.attachments?.length ? { attachments: input.attachments } : {}
284
+ ...input.attachments?.length ? { attachments: input.attachments } : {},
285
+ ...this.latestUserToken ? { userToken: this.latestUserToken } : {},
286
+ // This widget shows the approval card, so the server may pause writes for it.
287
+ confirmActions: true,
288
+ ...input.confirm ? { confirm: input.confirm } : {}
281
289
  };
282
290
  const response = await this.doFetch(`${this.baseUrl}/v1/chat`, {
283
291
  method: "POST",
@@ -312,7 +320,7 @@ var FrankieClient = class {
312
320
  await this.postToolResult(session, callId, result).catch(() => void 0);
313
321
  }
314
322
  async callHostApi(request) {
315
- const api = this.options.api;
323
+ const api = this.options.api ?? (typeof window !== "undefined" ? { baseUrl: window.location.origin } : void 0);
316
324
  if (!api) {
317
325
  return {
318
326
  status: 0,
@@ -419,6 +427,10 @@ function luminance([r, g, b]) {
419
427
  };
420
428
  return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
421
429
  }
430
+ function colorful([r, g, b]) {
431
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
432
+ return max - min >= 40;
433
+ }
422
434
  function contrastRatio(a, b) {
423
435
  const la = luminance(a), lb = luminance(b);
424
436
  return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
@@ -527,7 +539,7 @@ function inferHostTheme() {
527
539
  break;
528
540
  }
529
541
  const text = parseRgb(style.color);
530
- if (text && text[3] > 0.5 && !sameColor(text, foreground)) {
542
+ if (text && text[3] > 0.5 && !sameColor(text, foreground) && colorful(text)) {
531
543
  accent = text;
532
544
  break;
533
545
  }
@@ -605,6 +617,11 @@ function applyEvent(message, event) {
605
617
  } : tool
606
618
  )
607
619
  };
620
+ case "action_confirm":
621
+ return {
622
+ ...message,
623
+ action: { toolUseId: event.toolUseId, name: event.name, label: event.label, preview: event.preview, state: "pending" }
624
+ };
608
625
  case "tool_denied":
609
626
  return {
610
627
  ...message,
@@ -824,6 +841,7 @@ function useFrankieChatState() {
824
841
  ...context ? { context } : {},
825
842
  ...opts?.model ? { model: opts.model } : {},
826
843
  ...attachments.length ? { attachments } : {},
844
+ ...opts?.confirm ? { confirm: opts.confirm } : {},
827
845
  signal: abort.signal
828
846
  },
829
847
  (event) => {
@@ -894,6 +912,21 @@ function useFrankieChatState() {
894
912
  },
895
913
  [busy, client, context, patchAssistant, restored, followRunningTurn]
896
914
  );
915
+ const answerAction = (0, import_react.useCallback)(
916
+ async (toolUseId, approved) => {
917
+ if (abortRef.current) return;
918
+ const holder = messagesRef.current.find(
919
+ (message) => message.role === "assistant" && message.action?.toolUseId === toolUseId && message.action.state === "pending"
920
+ );
921
+ if (!holder) return;
922
+ patchAssistant(
923
+ holder.id,
924
+ (message) => message.action ? { ...message, action: { ...message.action, state: approved ? "approved" : "cancelled" } } : message
925
+ );
926
+ await send(approved ? "Go ahead" : "Cancel", { confirm: { toolUseId, approved } });
927
+ },
928
+ [patchAssistant, send]
929
+ );
897
930
  const stop = (0, import_react.useCallback)(() => {
898
931
  if (!abortRef.current) return;
899
932
  void client.stopTurn();
@@ -914,7 +947,7 @@ function useFrankieChatState() {
914
947
  } catch {
915
948
  }
916
949
  }, [client]);
917
- return { messages, busy, loadedSkills, activeApis, restoring: !restored, ...error ? { error } : {}, send, stop, reset };
950
+ return { messages, busy, loadedSkills, activeApis, restoring: !restored, ...error ? { error } : {}, send, answerAction, stop, reset };
918
951
  }
919
952
  function conversationTitle(messages) {
920
953
  const first = messages.find((message) => message.role === "user" && message.text.trim());
@@ -931,6 +964,7 @@ function stillWorking(messages) {
931
964
  // src/hooks/FrankieProvider.tsx
932
965
  var import_jsx_runtime = require("react/jsx-runtime");
933
966
  var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react2.useEffect : import_react2.useLayoutEffect;
967
+ var THEME_WAIT_MS = 5e3;
934
968
  var FrankieContext = (0, import_react2.createContext)(null);
935
969
  function FrankieProvider({
936
970
  children,
@@ -984,6 +1018,13 @@ function FrankieProvider({
984
1018
  setHostSampled(true);
985
1019
  return watchHostTheme(sample);
986
1020
  }, [inheriting]);
1021
+ const themeKnown = Boolean(config || configError) && (!inheriting || hostSampled);
1022
+ const [waitedForTheme, setWaitedForTheme] = (0, import_react2.useState)(false);
1023
+ (0, import_react2.useEffect)(() => {
1024
+ if (themeKnown) return;
1025
+ const timer = setTimeout(() => setWaitedForTheme(true), THEME_WAIT_MS);
1026
+ return () => clearTimeout(timer);
1027
+ }, [themeKnown]);
987
1028
  const value = (0, import_react2.useMemo)(
988
1029
  () => ({
989
1030
  client,
@@ -994,9 +1035,9 @@ function FrankieProvider({
994
1035
  ...theme ? { theme } : {},
995
1036
  injectStyles,
996
1037
  hostTheme,
997
- themeReady: Boolean(config || configError) && (!inheriting || hostSampled)
1038
+ themeReady: themeKnown || waitedForTheme
998
1039
  }),
999
- [client, config, configError, loading, context, theme, injectStyles, hostTheme, inheriting, hostSampled]
1040
+ [client, config, configError, loading, context, theme, injectStyles, hostTheme, themeKnown, waitedForTheme]
1000
1041
  );
1001
1042
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FrankieContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationState, { children }, client.namespace + ":" + (client.conversationId ?? "")) });
1002
1043
  }
@@ -1020,7 +1061,7 @@ function useFrankieTheme() {
1020
1061
  }
1021
1062
 
1022
1063
  // src/components/chat/FrankieWidget.tsx
1023
- var import_lucide_react8 = require("lucide-react");
1064
+ var import_lucide_react9 = require("lucide-react");
1024
1065
  var import_react11 = require("react");
1025
1066
 
1026
1067
  // src/lib/styles-ready.ts
@@ -1028,7 +1069,7 @@ var import_react3 = require("react");
1028
1069
 
1029
1070
  // src/generated/css-content.ts
1030
1071
  var FRANKIE_CSS_CONTENT = `/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
1031
- @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-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-ease:initial}}}@layer theme{.frankie-root{--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--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-medium:500;--font-weight-semibold:600;--leading-tight:1.25;--radius-md:.375rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-background:var(--frankie-background);--color-foreground:var(--frankie-foreground);--color-primary:var(--frankie-primary)}}@layer components{.frankie-page-shell{background:var(--frankie-background);height:100%;min-height:0;color:var(--frankie-foreground);flex:1;display:flex}.frankie-page-main{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.frankie-history-desktop{border-right:1px solid var(--frankie-border);background:var(--frankie-secondary);flex-direction:column;flex-shrink:0;gap:16px;width:260px;padding:20px 14px;transition:width .16s,padding .16s;display:flex;overflow:auto}.frankie-history-toggle{border:1px solid var(--frankie-border);background:var(--frankie-background);width:32px;height:32px;color:var(--frankie-muted-foreground);cursor:pointer;border-radius:8px;flex-shrink:0;justify-content:center;align-self:flex-end;align-items:center;display:flex}.frankie-history-toggle:hover{color:var(--frankie-foreground)}.frankie-history-collapsed{width:56px;padding:20px 8px;overflow:visible}.frankie-history-collapsed .frankie-history-toggle{align-self:center}.frankie-history-heading{justify-content:space-between;align-items:center;font-size:14px;display:flex}.frankie-new-chat{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;border-radius:10px;justify-content:center;align-items:center;gap:8px;min-height:44px;font-weight:600;display:flex}.frankie-history-search>span{color:var(--frankie-muted-foreground);margin-bottom:6px;font-size:12px;display:block}.frankie-history-search input{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:8px;width:100%;min-height:40px;padding:8px 10px}.frankie-history-list{flex-direction:column;flex:1;gap:4px;display:flex}.frankie-history-list button{text-align:left;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:8px;flex-direction:column;align-items:flex-start;gap:5px;min-height:54px;padding:10px;display:flex}.frankie-history-list button span{text-overflow:ellipsis;white-space:nowrap;width:100%;font-size:13px;overflow:hidden}.frankie-history-list small{color:var(--frankie-muted-foreground);font-size:11px}.frankie-history-list button:hover,.frankie-history-list button[aria-current]{background:var(--frankie-background);border-color:var(--frankie-border)}.frankie-history-desktop>p,.frankie-history-dialog p{color:var(--frankie-muted-foreground);font-size:13px}.frankie-header-caption{color:var(--frankie-muted-foreground);font-size:12px}.frankie-page-header button{cursor:pointer;justify-content:center;align-items:center;gap:6px;min-width:40px;min-height:40px;display:inline-flex}.frankie-chat-settings{position:relative}.frankie-chat-settings summary{cursor:pointer;border-radius:8px;place-items:center;width:40px;height:40px;list-style:none;display:grid}.frankie-chat-settings summary::-webkit-details-marker{display:none}.frankie-chat-settings>div{z-index:5;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:12px;gap:12px;width:min(280px,80vw);padding:16px;font-size:13px;display:grid;position:absolute;top:46px;right:0;box-shadow:0 10px 30px #0002}.frankie-chat-settings p{color:var(--frankie-muted-foreground);margin:0}.frankie-loaded-skills{width:100%;max-width:760px;color:var(--frankie-muted-foreground);font-size:12px}.frankie-loaded-skills summary{cursor:pointer;padding:6px 0}.frankie-loaded-skills ul{margin:0;padding:4px 0;list-style:none}.frankie-loaded-skills li{gap:8px;padding:4px 0;display:flex}.frankie-loaded-skills small{opacity:.7}.frankie-history-dialog{background:var(--frankie-secondary);width:min(320px,86vw);max-width:none;height:100dvh;max-height:none;color:var(--frankie-foreground);border:0;margin:0;padding:0}.frankie-history-dialog::backdrop{background:#0008}.frankie-history-dialog>aside{height:100%;padding:calc(20px + env(safe-area-inset-top)) 16px calc(20px + env(safe-area-inset-bottom));flex-direction:column;gap:16px;display:flex;overflow:auto}.frankie-mobile-only{display:none!important}.frankie-widget-panel{max-height:calc(100dvh - 100px - var(--frankie-lift,0px))}.frankie-root button:focus-visible,.frankie-root summary:focus-visible,.frankie-root input:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:3px}.frankie-root button:disabled{opacity:.5;cursor:not-allowed}@media (max-width:760px){.frankie-history-desktop{display:none}.frankie-mobile-only{display:inline-flex!important}.frankie-header-caption{display:none}.frankie-page-header{padding:6px 10px}.frankie-history-heading button{background:0 0;border:0;justify-content:center;align-items:center;min-width:44px;min-height:44px}.frankie-page-prompts{gap:8px}.frankie-widget-panel{width:calc(100vw - 32px)}}.frankie-root{--frankie-styles-ready:1;--frankie-background:#fff;--frankie-foreground:#0a0a0a;--frankie-primary:#171717;--frankie-primary-foreground:#fafafa;--frankie-secondary:#f5f5f5;--frankie-secondary-foreground:#171717;--frankie-muted:#f5f5f5;--frankie-muted-foreground:#737373;--frankie-border:#e5e5e5;--frankie-radius:.625rem;--frankie-font:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-family:var(--frankie-font);color:var(--frankie-foreground);-webkit-font-smoothing:antialiased;line-height:1.5}.frankie-root.dark{--frankie-background:#0a0a0a;--frankie-foreground:#fafafa;--frankie-primary:#fafafa;--frankie-primary-foreground:#171717;--frankie-secondary:#262626;--frankie-secondary-foreground:#fafafa;--frankie-muted:#262626;--frankie-muted-foreground:#a3a3a3;--frankie-border:#262626}.frankie-root,.frankie-root *,.frankie-root :before,.frankie-root :after{box-sizing:border-box}.frankie-root button,.frankie-root textarea,.frankie-root input{font:inherit;color:inherit;margin:0}.frankie-root button{background-color:#0000;border:0 solid}.frankie-root textarea{background-color:var(--frankie-background)}.frankie-focus:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:2px}.frankie-scroll{scrollbar-width:thin;scrollbar-color:var(--frankie-border) transparent}.frankie-prose>*+*{margin-top:.6rem}.frankie-prose p{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;line-height:1.6}.frankie-prose>.frankie-h{letter-spacing:-.01em;margin-top:1.15rem;line-height:1.3}.frankie-prose>.frankie-h:first-child{margin-top:0}.frankie-prose h3.frankie-h{font-size:1.06em;font-weight:700}.frankie-prose h4.frankie-h{font-size:1em;font-weight:600}.frankie-prose h5.frankie-h{color:var(--frankie-muted-foreground);font-size:.92em;font-weight:600}.frankie-prose strong{font-weight:600}.frankie-prose ul,.frankie-prose ol{flex-direction:column;gap:.35rem;margin:0;padding-left:1.4rem;display:flex}.frankie-prose li{padding-left:.15rem;line-height:1.55}.frankie-prose li::marker{color:var(--frankie-muted-foreground)}.frankie-prose ul{list-style:outside}.frankie-prose ol{list-style:decimal}.frankie-prose a{color:var(--frankie-primary);text-underline-offset:2px;text-decoration:underline}.frankie-prose code{background-color:var(--frankie-muted);border-radius:.25rem;padding:.1em .3em;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.85em}.frankie-prose pre{border-radius:var(--frankie-radius);background-color:var(--frankie-muted);margin:0;padding:.625rem .75rem;overflow-x:auto}.frankie-prose pre code{background:0 0;padding:0}.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, var(--frankie-primary), transparent 65%), var(--frankie-background);flex-direction:column;min-width:0;display:flex;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, color-mix(in srgb, var(--frankie-primary) 8%, transparent), transparent 65%), var(--frankie-background)}}.frankie-chat-page{color:var(--frankie-foreground)}.frankie-page-header{border-bottom:1px solid var(--frankie-border);background:var(--frankie-background);flex:0 0 56px;justify-content:space-between;align-items:center;gap:16px;min-height:56px;padding:0 24px;display:flex}@supports (color:color-mix(in lab, red, red)){.frankie-page-header{background:color-mix(in srgb, var(--frankie-background) 92%, transparent)}}.frankie-page-header{-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.frankie-page-header>div{align-items:center;gap:10px;display:flex}.frankie-page-header strong{font-size:.925rem;font-weight:650}.frankie-page-status{background:var(--frankie-primary);width:10px;height:10px;box-shadow:0 0 0 4px var(--frankie-primary);border-radius:999px}@supports (color:color-mix(in lab, red, red)){.frankie-page-status{box-shadow:0 0 0 4px color-mix(in srgb, var(--frankie-primary) 16%, transparent)}}.frankie-page-header button{border:1px solid var(--frankie-border);border-radius:calc(var(--frankie-radius) * .9);background:var(--frankie-secondary);cursor:pointer;min-height:36px;padding:0 13px}.frankie-page-header button:hover{border-color:var(--frankie-primary)}.frankie-page-canvas{flex:1;min-width:0;min-height:0;display:flex}.frankie-page-canvas>.frankie-inline{width:100%;max-width:56rem;margin:0 auto}.frankie-page-canvas .frankie-scroll{padding:2rem clamp(1rem,4vw,4rem) 1.25rem}.frankie-page-canvas .frankie-root>.border-t{background:linear-gradient(180deg, transparent, var(--frankie-background) 30%);border-top:0;padding:.75rem clamp(1rem,4vw,4rem) 1.5rem}.frankie-page-empty{text-align:center;flex-direction:column;flex-shrink:0;justify-content:safe center;align-items:center;gap:2rem;width:min(100%,44rem);min-height:100%;margin:auto;padding:clamp(2rem,7vh,4.5rem) 1rem 2rem;display:flex;container-type:inline-size}.frankie-page-welcome h1{letter-spacing:-.02em;margin:0;font-size:clamp(1.55rem,3.4vw,2rem);font-weight:700;line-height:1.15}.frankie-page-welcome p{max-width:34rem;color:var(--frankie-muted-foreground);margin:.6rem auto 0;font-size:1rem}.frankie-page-suggest{flex-direction:column;align-items:center;gap:1rem;width:100%;display:flex}.frankie-page-suggest-label{color:var(--frankie-muted-foreground);letter-spacing:.12em;text-transform:uppercase;margin:0;font-size:.72rem;font-weight:600}.frankie-page-prompts{grid-template-columns:1fr;gap:.75rem;width:100%;display:grid}@container (min-width:30rem){.frankie-page-prompts{grid-template-columns:repeat(2,minmax(0,1fr))}}.frankie-page-prompts button{border:1px solid var(--frankie-border);background:var(--frankie-background);text-align:left;cursor:pointer;border-radius:14px;align-items:flex-start;gap:.85rem;min-height:64px;padding:.9rem 1rem;transition:border-color .15s,background-color .15s,transform .12s;display:flex}.frankie-page-prompts button:hover:not(:disabled){border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-page-prompts button:hover:not(:disabled){border-color:color-mix(in srgb, var(--frankie-primary) 45%, var(--frankie-border))}}.frankie-page-prompts button:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-page-prompts button:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 4%, var(--frankie-background))}}.frankie-page-prompts button:hover:not(:disabled){transform:translateY(-1px)}.frankie-prompt-icon{background:var(--frankie-muted);width:34px;height:34px;color:var(--frankie-foreground);border-radius:9px;flex:none;place-items:center;display:grid}.frankie-prompt-text{flex-direction:column;gap:2px;min-width:0;display:flex}.frankie-prompt-text strong{font-size:.9rem;font-weight:600;line-height:1.3}.frankie-prompt-text small{color:var(--frankie-muted-foreground);font-size:.8rem;line-height:1.35;overflow:hidden}.frankie-page-suggest-hint{color:var(--frankie-muted-foreground);margin:0;font-size:.85rem}.frankie-widget-panel .frankie-page-empty{gap:1rem;padding:1rem .25rem}.frankie-widget-panel .frankie-page-welcome h1{font-size:1.25rem}.frankie-widget-panel .frankie-page-welcome p{margin-top:.35rem;font-size:.88rem;line-height:1.45}.frankie-widget-panel .frankie-page-suggest{gap:.55rem}.frankie-widget-panel .frankie-page-suggest-label{font-size:.66rem}.frankie-widget-panel .frankie-page-prompts{flex-wrap:wrap;justify-content:center;gap:.4rem;display:flex}.frankie-widget-panel .frankie-page-prompts button{border-radius:999px;align-items:center;gap:.4rem;max-width:100%;min-height:34px;padding:.3rem .8rem .3rem .45rem}.frankie-widget-panel .frankie-prompt-icon{border-radius:999px;width:22px;height:22px}.frankie-widget-panel .frankie-prompt-icon svg{width:13px;height:13px}.frankie-widget-panel .frankie-prompt-text strong{white-space:nowrap;text-overflow:ellipsis;font-size:.82rem;font-weight:550;overflow:hidden}.frankie-widget-panel .frankie-prompt-text small,.frankie-widget-panel .frankie-page-suggest-hint{display:none}@media (max-width:640px){.frankie-page-header{flex-basis:52px;min-height:52px;padding:0 12px}.frankie-page-canvas .frankie-scroll{padding:1.25rem .75rem .5rem}.frankie-page-canvas .frankie-root>.border-t{padding:.65rem .75rem calc(.65rem + env(safe-area-inset-bottom))}}}@layer utilities;.frankie-root .\\@container{container-type:inline-size}.frankie-root .invisible{visibility:hidden}.frankie-root .visible{visibility:visible}.frankie-root .absolute{position:absolute}.frankie-root .fixed{position:fixed}.frankie-root .relative{position:relative}.frankie-root .static{position:static}.frankie-root .sticky{position:sticky}.frankie-root .isolate{isolation:isolate}.frankie-root .container{width:100%}@media (min-width:40rem){.frankie-root .container{max-width:40rem}}@media (min-width:48rem){.frankie-root .container{max-width:48rem}}@media (min-width:64rem){.frankie-root .container{max-width:64rem}}@media (min-width:80rem){.frankie-root .container{max-width:80rem}}@media (min-width:96rem){.frankie-root .container{max-width:96rem}}.frankie-root .mt-0{margin-top:0}.frankie-root .mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.frankie-root .mt-1{margin-top:var(--spacing)}.frankie-root .mt-2{margin-top:calc(var(--spacing) * 2)}.frankie-root .block{display:block}.frankie-root .contents{display:contents}.frankie-root .flex{display:flex}.frankie-root .grid{display:grid}.frankie-root .hidden{display:none}.frankie-root .inline{display:inline}.frankie-root .inline-flex{display:inline-flex}.frankie-root .table{display:table}.frankie-root .size-1{width:var(--spacing);height:var(--spacing)}.frankie-root .size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.frankie-root .size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.frankie-root .size-3\\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.frankie-root .size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.frankie-root .size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.frankie-root .size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.frankie-root .size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.frankie-root .size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.frankie-root .size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.frankie-root .size-full{width:100%;height:100%}.frankie-root .h-8{height:calc(var(--spacing) * 8)}.frankie-root .h-9{height:calc(var(--spacing) * 9)}.frankie-root .h-10{height:calc(var(--spacing) * 10)}.frankie-root .h-\\[32rem\\]{height:32rem}.frankie-root .h-full{height:100%}.frankie-root .h-px{height:1px}.frankie-root .min-h-7{min-height:calc(var(--spacing) * 7)}.frankie-root .min-h-\\[2\\.25rem\\]{min-height:2.25rem}.frankie-root .min-h-screen{min-height:100vh}.frankie-root .w-\\[22rem\\]{width:22rem}.frankie-root .w-full{width:100%}.frankie-root .max-w-\\[12rem\\]{max-width:12rem}.frankie-root .max-w-\\[14rem\\]{max-width:14rem}.frankie-root .max-w-\\[85\\%\\]{max-width:85%}.frankie-root .max-w-\\[calc\\(100vw-2rem\\)\\]{max-width:calc(100vw - 2rem)}.frankie-root .min-w-0{min-width:0}.frankie-root .flex-1{flex:1}.frankie-root .shrink-0{flex-shrink:0}.frankie-root .grow{flex-grow:1}.frankie-root .animate-pulse{animation:var(--animate-pulse)}.frankie-root .animate-spin{animation:var(--animate-spin)}.frankie-root .cursor-pointer{cursor:pointer}.frankie-root .resize{resize:both}.frankie-root .resize-none{resize:none}.frankie-root .list-none{list-style-type:none}.frankie-root .flex-col{flex-direction:column}.frankie-root .flex-wrap{flex-wrap:wrap}.frankie-root .items-center{align-items:center}.frankie-root .items-end{align-items:flex-end}.frankie-root .items-start{align-items:flex-start}.frankie-root .justify-center{justify-content:center}.frankie-root .justify-end{justify-content:flex-end}.frankie-root .gap-1{gap:var(--spacing)}.frankie-root .gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.frankie-root .gap-2{gap:calc(var(--spacing) * 2)}.frankie-root .gap-3{gap:calc(var(--spacing) * 3)}.frankie-root .gap-4{gap:calc(var(--spacing) * 4)}.frankie-root .truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.frankie-root .overflow-hidden{overflow:hidden}.frankie-root .overflow-y-auto{overflow-y:auto}.frankie-root .overscroll-contain{overscroll-behavior:contain}.frankie-root .rounded{border-radius:.25rem}.frankie-root .rounded-\\[calc\\(var\\(--frankie-radius\\)\\+4px\\)\\]{border-radius:calc(var(--frankie-radius) + 4px)}.frankie-root .rounded-\\[calc\\(var\\(--frankie-radius\\)-2px\\)\\]{border-radius:calc(var(--frankie-radius) - 2px)}.frankie-root .rounded-\\[var\\(--frankie-radius\\)\\]{border-radius:var(--frankie-radius)}.frankie-root .rounded-full{border-radius:3.40282e38px}.frankie-root .rounded-md{border-radius:var(--radius-md)}.frankie-root .rounded-none{border-radius:0}.frankie-root .border{border-style:var(--tw-border-style);border-width:1px}.frankie-root .border-0{border-style:var(--tw-border-style);border-width:0}.frankie-root .border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.frankie-root .border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.frankie-root .border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.frankie-root .border-border{border-color:var(--frankie-border)}.frankie-root .border-transparent{border-color:#0000}.frankie-root .bg-background{background-color:var(--frankie-background)}.frankie-root .bg-border{background-color:var(--frankie-border)}.frankie-root .bg-emerald-500{background-color:var(--color-emerald-500)}.frankie-root .bg-emerald-500\\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.frankie-root .bg-emerald-500\\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.frankie-root .bg-muted{background-color:var(--frankie-muted)}.frankie-root .bg-muted-foreground{background-color:var(--frankie-muted-foreground)}.frankie-root .bg-primary{background-color:var(--frankie-primary)}.frankie-root .bg-red-500{background-color:var(--color-red-500)}.frankie-root .bg-red-500\\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.frankie-root .bg-red-500\\/10{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.frankie-root .bg-secondary{background-color:var(--frankie-secondary)}.frankie-root .object-cover{object-fit:cover}.frankie-root .p-3{padding:calc(var(--spacing) * 3)}.frankie-root .p-4{padding:calc(var(--spacing) * 4)}.frankie-root .px-1{padding-inline:var(--spacing)}.frankie-root .px-2{padding-inline:calc(var(--spacing) * 2)}.frankie-root .px-3{padding-inline:calc(var(--spacing) * 3)}.frankie-root .px-4{padding-inline:calc(var(--spacing) * 4)}.frankie-root .px-6{padding-inline:calc(var(--spacing) * 6)}.frankie-root .py-0{padding-block:0}.frankie-root .py-0\\.5{padding-block:calc(var(--spacing) * .5)}.frankie-root .py-1{padding-block:var(--spacing)}.frankie-root .py-2{padding-block:calc(var(--spacing) * 2)}.frankie-root .py-3{padding-block:calc(var(--spacing) * 3)}.frankie-root .pl-2{padding-left:calc(var(--spacing) * 2)}.frankie-root .text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.frankie-root .text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.frankie-root .text-\\[0\\.625rem\\]{font-size:.625rem}.frankie-root .text-\\[0\\.6875rem\\]{font-size:.6875rem}.frankie-root .text-\\[11px\\]{font-size:11px}.frankie-root .leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.frankie-root .font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.frankie-root .font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.frankie-root .whitespace-nowrap{white-space:nowrap}.frankie-root .text-emerald-600{color:var(--color-emerald-600)}.frankie-root .text-foreground{color:var(--frankie-foreground)}.frankie-root .text-muted-foreground{color:var(--frankie-muted-foreground)}.frankie-root .text-primary{color:var(--frankie-primary)}.frankie-root .text-primary-foreground{color:var(--frankie-primary-foreground)}.frankie-root .text-red-600{color:var(--color-red-600)}.frankie-root .text-secondary-foreground{color:var(--frankie-secondary-foreground)}.frankie-root .italic{font-style:italic}.frankie-root .underline-offset-4{text-underline-offset:4px}.frankie-root .opacity-60{opacity:.6}.frankie-root .opacity-70{opacity:.7}.frankie-root .shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .outline{outline-style:var(--tw-outline-style);outline-width:1px}.frankie-root .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))}.frankie-root .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))}.frankie-root .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))}.frankie-root .ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.frankie-root .select-all{-webkit-user-select:all;user-select:all}.frankie-root .placeholder\\:text-muted-foreground::placeholder{color:var(--frankie-muted-foreground)}@media (hover:hover){.frankie-root .hover\\:border-border:hover{border-color:var(--frankie-border)}.frankie-root .hover\\:bg-muted:hover{background-color:var(--frankie-muted)}.frankie-root .hover\\:text-foreground:hover{color:var(--frankie-foreground)}.frankie-root .hover\\:underline:hover{text-decoration-line:underline}.frankie-root .hover\\:opacity-90:hover{opacity:.9}.frankie-root .hover\\:opacity-100:hover{opacity:1}}.frankie-root .focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + 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)}.frankie-root .focus-visible\\:ring-primary:focus-visible{--tw-ring-color:var(--frankie-primary)}.frankie-root .focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.frankie-root .disabled\\:pointer-events-none:disabled{pointer-events:none}.frankie-root .disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.frankie-root .disabled\\:opacity-50:disabled{opacity:.5}.frankie-root .dark\\:text-emerald-400:where(.dark,.dark *){color:var(--color-emerald-400)}.frankie-root .dark\\:text-red-400:where(.dark,.dark *){color:var(--color-red-400)}.frankie-root .\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.frankie-root .\\[\\&_svg\\]\\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.frankie-root .\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.frankie-root .\\[\\&\\:\\:-webkit-details-marker\\]\\:hidden::-webkit-details-marker{display:none}.frankie-root.frankie-chat-panel{min-height:0;position:relative}.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px var(--frankie-primary), 0 12px 28px -12px #0f172a47, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px color-mix(in srgb, var(--frankie-primary) 22%, #0f172a6b), 0 12px 28px -12px #0f172a47, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 8%, transparent)}}.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 12%, transparent)}}.frankie-root .frankie-agent-context-wrap{flex:none;justify-content:center;padding:12px 10px;display:flex}.frankie-root .frankie-agent-context{max-width:100%;color:var(--frankie-foreground);font-size:13px;position:relative}.frankie-root .frankie-agent-context>summary{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:10px;min-height:44px;padding:7px 13px;list-style:none;display:flex;box-shadow:0 1px 3px #0000000d}.frankie-root .frankie-agent-context>summary::-webkit-details-marker{display:none}.frankie-root .frankie-agent-context>summary>svg{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-context-count{background:var(--frankie-muted);color:var(--frankie-muted-foreground);border-radius:999px;padding:2px 10px;font-size:12px}.frankie-root .frankie-context-status{color:var(--frankie-muted-foreground);align-items:center;gap:6px;font-size:12px;display:flex}.frankie-root .frankie-context-status i{background:currentColor;border-radius:50%;width:7px;height:7px}.frankie-root .frankie-context-status[data-active=true]{color:#00976b}.frankie-root .frankie-context-detail{z-index:10;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:16px;width:340px;max-width:calc(100vw - 32px);padding:18px;position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);box-shadow:0 12px 32px #00000016}.frankie-root .frankie-context-detail p{color:var(--frankie-muted-foreground);margin:10px 0 0;font-size:12px;line-height:1.6}.frankie-root .frankie-context-detail ul{max-height:220px;margin:12px 0;padding:0;list-style:none;overflow:auto}.frankie-root .frankie-context-detail li{border-bottom:1px solid var(--frankie-border);overflow-wrap:anywhere;justify-content:space-between;gap:12px;padding:8px 0;display:flex}.frankie-root .frankie-context-detail small{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.frankie-root.frankie-chat-panel-fill{--frankie-canvas:var(--frankie-background)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill{--frankie-canvas:color-mix(in srgb,var(--frankie-background) 60%,var(--frankie-muted))}}.frankie-root.frankie-chat-panel-fill{background:var(--frankie-canvas)}.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:44px 16px 26px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:14px max(24px,50% - 480px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-message-list{gap:38px}.frankie-root.frankie-chat-panel-fill .frankie-user-bubble{background:var(--frankie-muted);color:var(--frankie-foreground);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:24px;padding:12px 20px;font-size:15px}.frankie-root.frankie-chat-panel-fill .frankie-assistant-content{flex:1;max-width:100%;font-size:15px;line-height:1.7}.frankie-root.frankie-chat-panel-fill .frankie-assistant-message{gap:14px}.frankie-root .frankie-thinking{color:var(--frankie-muted-foreground);gap:5px}.frankie-root .frankie-thinking-label{margin-right:6px;font-size:14px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{background:0 0;border:0;flex:none;padding:16px max(24px,50% - 500px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-composer{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:28px;padding:14px;box-shadow:0 2px 4px #0000000a}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:color-mix(in srgb,var(--frankie-foreground) 32%,var(--frankie-border))}}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px color-mix(in srgb,var(--frankie-primary) 8%,transparent)}}.frankie-root.frankie-chat-panel-fill .frankie-composer-controls{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.frankie-root.frankie-chat-panel-fill .frankie-composer textarea{resize:none;width:100%;min-height:32px;max-height:140px;color:var(--frankie-foreground);box-shadow:none;background:0 0;border:0;border-radius:0;outline:none;flex:0 0 100%;order:-1;margin-bottom:4px;padding:2px 6px;font-size:16px}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Send],.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Stop]{background:var(--frankie-primary);width:42px;height:42px;color:var(--frankie-primary-foreground);border:0;border-radius:50%;margin-left:auto}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Attach\\ files]{border-radius:50%;width:42px;height:42px}.frankie-root .frankie-composer-actions{align-items:center;gap:6px;min-width:0;display:flex}.frankie-root .frankie-composer-meta{align-items:center;gap:8px;margin-top:6px;padding:0 2px;display:flex}.frankie-root .frankie-model-picker{align-items:center;min-width:0;display:inline-flex}.frankie-root .frankie-model-select{appearance:none;max-width:12rem;color:var(--frankie-muted-foreground);font:inherit;cursor:pointer;text-overflow:ellipsis;background-color:#0000;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b8b8b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");background-position:right 6px center;background-repeat:no-repeat;background-size:11px;border:0;border-radius:8px;padding:5px 22px 5px 8px;font-size:12px;font-weight:500;line-height:1;transition:background-color .12s,color .12s}.frankie-root .frankie-model-select:hover{background-color:var(--frankie-muted);color:var(--frankie-foreground)}.frankie-root .frankie-model-select:disabled{opacity:.5;cursor:not-allowed}.frankie-root .frankie-model-select option{color:var(--frankie-foreground);background:var(--frankie-background);font-weight:400}.frankie-root .frankie-history-desktop{background:var(--frankie-background);width:290px;padding:20px 12px}.frankie-root .frankie-history-collapsed{width:56px;padding:20px 8px}.frankie-root .frankie-new-chat{background:0 0;border:0;justify-content:flex-start;padding:8px 12px;font-size:15px}.frankie-root .frankie-history-heading{color:var(--frankie-muted-foreground);padding:0 12px;font-size:12px;font-weight:400}.frankie-root .frankie-history-list button{min-height:44px;padding:10px 12px}.frankie-root .frankie-history-list button span{font-size:14px}.frankie-root .frankie-history-list button[aria-current],.frankie-root .frankie-history-list button:hover{background:var(--frankie-muted);border-color:#0000}.frankie-root .frankie-history-list small{display:none}.frankie-root .frankie-history-group{flex-direction:column;gap:2px;display:flex}.frankie-root .frankie-history-group+.frankie-history-group{margin-top:12px}.frankie-root .frankie-history-group-label{letter-spacing:.04em;color:var(--frankie-muted-foreground);margin:0;padding:4px 12px;font-size:11px;font-weight:600}.frankie-root .frankie-page-header{background:var(--frankie-background);height:56px;min-height:56px}.frankie-root .frankie-page-header>div{min-width:0}.frankie-root .frankie-thread-title{text-overflow:ellipsis;white-space:nowrap;max-width:55vw;font-weight:500;overflow:hidden}.frankie-root .frankie-page-header button{background:0 0;border-color:#0000}.frankie-root .frankie-page-canvas>.frankie-inline{max-width:none}@media (max-width:760px){.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:20px 8px 14px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:12px 16px 16px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{padding:10px 12px calc(12px + env(safe-area-inset-bottom))}.frankie-root .frankie-agent-context>summary{gap:6px;padding:7px 9px;font-size:12px}.frankie-root .frankie-context-count{padding:2px 7px;font-size:11px}.frankie-root .frankie-context-status{gap:4px;font-size:11px}.frankie-root .frankie-agent-context>summary>svg{width:14px}.frankie-root .frankie-thread-title{max-width:42vw}}.frankie-root .frankie-agent-context>summary>svg:first-child{box-sizing:content-box;background:var(--frankie-muted);border-radius:50%;padding:4px}.frankie-root.frankie-chat-panel-fill .frankie-agent-context>summary{font-size:14px}.frankie-root .frankie-agent-context>summary>span:first-of-type{border-right:1px solid var(--frankie-border);padding-right:10px}@media (max-width:760px){.frankie-root .frankie-page-header button>span{display:none}}.frankie-root .frankie-choices{flex-direction:column;gap:8px;margin-top:12px;display:flex}.frankie-root .frankie-choice{text-align:left;cursor:pointer;border:1px solid var(--frankie-border);border-radius:var(--frankie-radius);background:var(--frankie-background);width:100%;color:var(--frankie-foreground);font:inherit;align-items:center;gap:12px;padding:11px 14px;font-size:14px;line-height:1.4;transition:border-color .15s,background-color .15s,transform .12s;display:flex}.frankie-root .frankie-choice:hover:not(:disabled){border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){border-color:color-mix(in srgb, var(--frankie-primary) 55%, var(--frankie-border))}}.frankie-root .frankie-choice:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 6%, var(--frankie-background))}}.frankie-root .frankie-choice:active:not(:disabled){transform:scale(.99)}.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px var(--frankie-primary);outline:none}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, var(--frankie-primary) 40%, transparent)}}.frankie-root .frankie-choice:disabled{opacity:.6;cursor:default}.frankie-root .frankie-choice-index{border:1px solid var(--frankie-border);background:var(--frankie-muted);width:24px;height:24px;color:var(--frankie-muted-foreground);border-radius:50%;flex:none;place-items:center;font-size:12px;font-weight:600;transition:background-color .15s,color .15s,border-color .15s;display:grid}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-primary);border-color:var(--frankie-primary);color:var(--frankie-primary-foreground)}.frankie-root .frankie-choice-label{flex:1;min-width:0}.frankie-root .frankie-choice-go{color:var(--frankie-muted-foreground);opacity:0;flex:none;transition:opacity .15s,transform .15s;transform:translate(-4px)}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-go{opacity:1;color:var(--frankie-primary);transform:none}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-choice,.frankie-root .frankie-choice-go,.frankie-root .frankie-choice-index{transition:none}}.frankie-root .frankie-choice-other{color:var(--frankie-muted-foreground);border-style:dashed}.frankie-root .frankie-choice-other .frankie-choice-index{background:0 0}.frankie-root .frankie-choice-other:hover:not(:disabled){color:var(--frankie-foreground)}.frankie-root .frankie-choice-other:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-muted);border-color:var(--frankie-border);color:var(--frankie-foreground)}.frankie-root .frankie-choice-hint{color:var(--frankie-muted-foreground);flex:none;font-size:12px}.frankie-root .frankie-skeleton{flex-direction:column;gap:8px;max-width:min(420px,100%);padding:4px 0 6px;display:flex}.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, var(--frankie-muted-foreground) 25%, var(--frankie-muted-foreground) 37%, var(--frankie-muted-foreground) 63%);border-radius:6px;height:12px}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 25%, color-mix(in srgb, var(--frankie-muted-foreground) 19%, transparent) 37%, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 63%)}}.frankie-root .frankie-skeleton-line{background-size:400% 100%;animation:2.2s ease-in-out infinite frankie-shimmer}.frankie-root .frankie-skeleton.is-delayed{animation:.25s .35s both frankie-skeleton-in}@keyframes frankie-skeleton-in{0%{opacity:0}to{opacity:1}}@keyframes frankie-shimmer{0%{background-position:100%}to{background-position:0}}@keyframes frankie-skeleton-pulse{0%,to{opacity:.45}50%{opacity:.85}}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-skeleton-line{background:var(--frankie-muted-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:color-mix(in srgb, var(--frankie-muted-foreground) 16%, transparent)}}.frankie-root .frankie-skeleton-line{animation:1.6s ease-in-out infinite frankie-skeleton-pulse}}@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-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-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}`;
1072
+ @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-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-ease:initial}}}@layer theme{.frankie-root{--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--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-medium:500;--font-weight-semibold:600;--leading-tight:1.25;--radius-md:.375rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-background:var(--frankie-background);--color-foreground:var(--frankie-foreground);--color-primary:var(--frankie-primary)}}@layer components{.frankie-page-shell{background:var(--frankie-background);height:100%;min-height:0;color:var(--frankie-foreground);flex:1;display:flex}.frankie-page-main{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.frankie-history-desktop{border-right:1px solid var(--frankie-border);background:var(--frankie-secondary);flex-direction:column;flex-shrink:0;gap:16px;width:260px;padding:20px 14px;transition:width .16s,padding .16s;display:flex;overflow:auto}.frankie-history-toggle{border:1px solid var(--frankie-border);background:var(--frankie-background);width:32px;height:32px;color:var(--frankie-muted-foreground);cursor:pointer;border-radius:8px;flex-shrink:0;justify-content:center;align-self:flex-end;align-items:center;display:flex}.frankie-history-toggle:hover{color:var(--frankie-foreground)}.frankie-history-collapsed{width:56px;padding:20px 8px;overflow:visible}.frankie-history-collapsed .frankie-history-toggle{align-self:center}.frankie-history-heading{justify-content:space-between;align-items:center;font-size:14px;display:flex}.frankie-new-chat{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;border-radius:10px;justify-content:center;align-items:center;gap:8px;min-height:44px;font-weight:600;display:flex}.frankie-history-search>span{color:var(--frankie-muted-foreground);margin-bottom:6px;font-size:12px;display:block}.frankie-history-search input{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:8px;width:100%;min-height:40px;padding:8px 10px}.frankie-history-list{flex-direction:column;flex:1;gap:4px;display:flex}.frankie-history-list button{text-align:left;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:8px;flex-direction:column;align-items:flex-start;gap:5px;min-height:54px;padding:10px;display:flex}.frankie-history-list button span{text-overflow:ellipsis;white-space:nowrap;width:100%;font-size:13px;overflow:hidden}.frankie-history-list small{color:var(--frankie-muted-foreground);font-size:11px}.frankie-history-list button:hover,.frankie-history-list button[aria-current]{background:var(--frankie-background);border-color:var(--frankie-border)}.frankie-history-desktop>p,.frankie-history-dialog p{color:var(--frankie-muted-foreground);font-size:13px}.frankie-header-caption{color:var(--frankie-muted-foreground);font-size:12px}.frankie-page-header button{cursor:pointer;justify-content:center;align-items:center;gap:6px;min-width:40px;min-height:40px;display:inline-flex}.frankie-chat-settings{position:relative}.frankie-chat-settings summary{cursor:pointer;border-radius:8px;place-items:center;width:40px;height:40px;list-style:none;display:grid}.frankie-chat-settings summary::-webkit-details-marker{display:none}.frankie-chat-settings>div{z-index:5;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:12px;gap:12px;width:min(280px,80vw);padding:16px;font-size:13px;display:grid;position:absolute;top:46px;right:0;box-shadow:0 10px 30px #0002}.frankie-chat-settings p{color:var(--frankie-muted-foreground);margin:0}.frankie-loaded-skills{width:100%;max-width:760px;color:var(--frankie-muted-foreground);font-size:12px}.frankie-loaded-skills summary{cursor:pointer;padding:6px 0}.frankie-loaded-skills ul{margin:0;padding:4px 0;list-style:none}.frankie-loaded-skills li{gap:8px;padding:4px 0;display:flex}.frankie-loaded-skills small{opacity:.7}.frankie-history-dialog{background:var(--frankie-secondary);width:min(320px,86vw);max-width:none;height:100dvh;max-height:none;color:var(--frankie-foreground);border:0;margin:0;padding:0}.frankie-history-dialog::backdrop{background:#0008}.frankie-history-dialog>aside{height:100%;padding:calc(20px + env(safe-area-inset-top)) 16px calc(20px + env(safe-area-inset-bottom));flex-direction:column;gap:16px;display:flex;overflow:auto}.frankie-mobile-only{display:none!important}.frankie-widget-panel{max-height:calc(100dvh - 100px - var(--frankie-lift,0px))}.frankie-root button:focus-visible,.frankie-root summary:focus-visible,.frankie-root input:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:3px}.frankie-root button:disabled{opacity:.5;cursor:not-allowed}@media (max-width:760px){.frankie-history-desktop{display:none}.frankie-mobile-only{display:inline-flex!important}.frankie-header-caption{display:none}.frankie-page-header{padding:6px 10px}.frankie-history-heading button{background:0 0;border:0;justify-content:center;align-items:center;min-width:44px;min-height:44px}.frankie-page-prompts{gap:8px}.frankie-widget-panel{width:calc(100vw - 32px)}}.frankie-root{--frankie-styles-ready:1;--frankie-background:#fff;--frankie-foreground:#0a0a0a;--frankie-primary:#171717;--frankie-primary-foreground:#fafafa;--frankie-secondary:#f5f5f5;--frankie-secondary-foreground:#171717;--frankie-muted:#f5f5f5;--frankie-muted-foreground:#737373;--frankie-border:#e5e5e5;--frankie-radius:.625rem;--frankie-font:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-family:var(--frankie-font);color:var(--frankie-foreground);-webkit-font-smoothing:antialiased;line-height:1.5}.frankie-root.dark{--frankie-background:#0a0a0a;--frankie-foreground:#fafafa;--frankie-primary:#fafafa;--frankie-primary-foreground:#171717;--frankie-secondary:#262626;--frankie-secondary-foreground:#fafafa;--frankie-muted:#262626;--frankie-muted-foreground:#a3a3a3;--frankie-border:#262626}.frankie-root,.frankie-root *,.frankie-root :before,.frankie-root :after{box-sizing:border-box}.frankie-root button,.frankie-root textarea,.frankie-root input{font:inherit;color:inherit;margin:0}.frankie-root button{background-color:#0000;border:0 solid}.frankie-root textarea{background-color:var(--frankie-background)}.frankie-focus:focus-visible{outline:2px solid var(--frankie-primary);outline-offset:2px}.frankie-scroll{scrollbar-width:thin;scrollbar-color:var(--frankie-border) transparent}.frankie-prose>*+*{margin-top:.6rem}.frankie-prose p{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;line-height:1.6}.frankie-prose>.frankie-h{letter-spacing:-.01em;margin-top:1.15rem;line-height:1.3}.frankie-prose>.frankie-h:first-child{margin-top:0}.frankie-prose h3.frankie-h{font-size:1.06em;font-weight:700}.frankie-prose h4.frankie-h{font-size:1em;font-weight:600}.frankie-prose h5.frankie-h{color:var(--frankie-muted-foreground);font-size:.92em;font-weight:600}.frankie-prose strong{font-weight:600}.frankie-prose ul,.frankie-prose ol{flex-direction:column;gap:.35rem;margin:0;padding-left:1.4rem;display:flex}.frankie-prose li{padding-left:.15rem;line-height:1.55}.frankie-prose li::marker{color:var(--frankie-muted-foreground)}.frankie-prose ul{list-style:outside}.frankie-prose ol{list-style:decimal}.frankie-prose a{color:var(--frankie-primary);text-underline-offset:2px;text-decoration:underline}.frankie-prose code{background-color:var(--frankie-muted);border-radius:.25rem;padding:.1em .3em;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.85em}.frankie-prose pre{border-radius:var(--frankie-radius);background-color:var(--frankie-muted);margin:0;padding:.625rem .75rem;overflow-x:auto}.frankie-prose pre code{background:0 0;padding:0}.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, var(--frankie-primary), transparent 65%), var(--frankie-background);flex-direction:column;min-width:0;display:flex;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.frankie-chat-page{background:radial-gradient(60rem 24rem at 50% -12rem, color-mix(in srgb, var(--frankie-primary) 8%, transparent), transparent 65%), var(--frankie-background)}}.frankie-chat-page{color:var(--frankie-foreground)}.frankie-page-header{border-bottom:1px solid var(--frankie-border);background:var(--frankie-background);flex:0 0 56px;justify-content:space-between;align-items:center;gap:16px;min-height:56px;padding:0 24px;display:flex}@supports (color:color-mix(in lab, red, red)){.frankie-page-header{background:color-mix(in srgb, var(--frankie-background) 92%, transparent)}}.frankie-page-header{-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.frankie-page-header>div{align-items:center;gap:10px;display:flex}.frankie-page-header strong{font-size:.925rem;font-weight:650}.frankie-page-status{background:var(--frankie-primary);width:10px;height:10px;box-shadow:0 0 0 4px var(--frankie-primary);border-radius:999px}@supports (color:color-mix(in lab, red, red)){.frankie-page-status{box-shadow:0 0 0 4px color-mix(in srgb, var(--frankie-primary) 16%, transparent)}}.frankie-page-header button{border:1px solid var(--frankie-border);border-radius:calc(var(--frankie-radius) * .9);background:var(--frankie-secondary);cursor:pointer;min-height:36px;padding:0 13px}.frankie-page-header button:hover{border-color:var(--frankie-primary)}.frankie-page-canvas{flex:1;min-width:0;min-height:0;display:flex}.frankie-page-canvas>.frankie-inline{width:100%;max-width:56rem;margin:0 auto}.frankie-page-canvas .frankie-scroll{padding:2rem clamp(1rem,4vw,4rem) 1.25rem}.frankie-page-canvas .frankie-root>.border-t{background:linear-gradient(180deg, transparent, var(--frankie-background) 30%);border-top:0;padding:.75rem clamp(1rem,4vw,4rem) 1.5rem}.frankie-page-empty{text-align:center;flex-direction:column;flex-shrink:0;justify-content:safe center;align-items:center;gap:2rem;width:min(100%,44rem);min-height:100%;margin:auto;padding:clamp(2rem,7vh,4.5rem) 1rem 2rem;display:flex;container-type:inline-size}.frankie-page-welcome h1{letter-spacing:-.02em;margin:0;font-size:clamp(1.55rem,3.4vw,2rem);font-weight:700;line-height:1.15}.frankie-page-welcome p{max-width:34rem;color:var(--frankie-muted-foreground);margin:.6rem auto 0;font-size:1rem}.frankie-page-suggest{flex-direction:column;align-items:center;gap:1rem;width:100%;display:flex}.frankie-page-suggest-label{color:var(--frankie-muted-foreground);letter-spacing:.12em;text-transform:uppercase;margin:0;font-size:.72rem;font-weight:600}.frankie-page-prompts{grid-template-columns:1fr;gap:.75rem;width:100%;display:grid}@container (min-width:30rem){.frankie-page-prompts{grid-template-columns:repeat(2,minmax(0,1fr))}}.frankie-page-prompts button{border:1px solid var(--frankie-border);background:var(--frankie-background);text-align:left;cursor:pointer;border-radius:14px;align-items:flex-start;gap:.85rem;min-height:64px;padding:.9rem 1rem;transition:border-color .15s,background-color .15s,transform .12s;display:flex}.frankie-page-prompts button:hover:not(:disabled){border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-page-prompts button:hover:not(:disabled){border-color:color-mix(in srgb, var(--frankie-primary) 45%, var(--frankie-border))}}.frankie-page-prompts button:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-page-prompts button:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 4%, var(--frankie-background))}}.frankie-page-prompts button:hover:not(:disabled){transform:translateY(-1px)}.frankie-prompt-icon{background:var(--frankie-muted);width:34px;height:34px;color:var(--frankie-foreground);border-radius:9px;flex:none;place-items:center;display:grid}.frankie-prompt-text{flex-direction:column;gap:2px;min-width:0;display:flex}.frankie-prompt-text strong{font-size:.9rem;font-weight:600;line-height:1.3}.frankie-prompt-text small{color:var(--frankie-muted-foreground);font-size:.8rem;line-height:1.35;overflow:hidden}.frankie-page-suggest-hint{color:var(--frankie-muted-foreground);margin:0;font-size:.85rem}.frankie-widget-panel .frankie-page-empty{gap:1rem;padding:1rem .25rem}.frankie-widget-panel .frankie-page-welcome h1{font-size:1.25rem}.frankie-widget-panel .frankie-page-welcome p{margin-top:.35rem;font-size:.88rem;line-height:1.45}.frankie-widget-panel .frankie-page-suggest{gap:.55rem}.frankie-widget-panel .frankie-page-suggest-label{font-size:.66rem}.frankie-widget-panel .frankie-page-prompts{flex-wrap:wrap;justify-content:center;gap:.4rem;display:flex}.frankie-widget-panel .frankie-page-prompts button{border-radius:999px;align-items:center;gap:.4rem;max-width:100%;min-height:34px;padding:.3rem .8rem .3rem .45rem}.frankie-widget-panel .frankie-prompt-icon{border-radius:999px;width:22px;height:22px}.frankie-widget-panel .frankie-prompt-icon svg{width:13px;height:13px}.frankie-widget-panel .frankie-prompt-text strong{white-space:nowrap;text-overflow:ellipsis;font-size:.82rem;font-weight:550;overflow:hidden}.frankie-widget-panel .frankie-prompt-text small,.frankie-widget-panel .frankie-page-suggest-hint{display:none}@media (max-width:640px){.frankie-page-header{flex-basis:52px;min-height:52px;padding:0 12px}.frankie-page-canvas .frankie-scroll{padding:1.25rem .75rem .5rem}.frankie-page-canvas .frankie-root>.border-t{padding:.65rem .75rem calc(.65rem + env(safe-area-inset-bottom))}}}@layer utilities;.frankie-root .\\@container{container-type:inline-size}.frankie-root .invisible{visibility:hidden}.frankie-root .visible{visibility:visible}.frankie-root .absolute{position:absolute}.frankie-root .fixed{position:fixed}.frankie-root .relative{position:relative}.frankie-root .static{position:static}.frankie-root .sticky{position:sticky}.frankie-root .isolate{isolation:isolate}.frankie-root .container{width:100%}@media (min-width:40rem){.frankie-root .container{max-width:40rem}}@media (min-width:48rem){.frankie-root .container{max-width:48rem}}@media (min-width:64rem){.frankie-root .container{max-width:64rem}}@media (min-width:80rem){.frankie-root .container{max-width:80rem}}@media (min-width:96rem){.frankie-root .container{max-width:96rem}}.frankie-root .mt-0{margin-top:0}.frankie-root .mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.frankie-root .mt-1{margin-top:var(--spacing)}.frankie-root .mt-2{margin-top:calc(var(--spacing) * 2)}.frankie-root .block{display:block}.frankie-root .contents{display:contents}.frankie-root .flex{display:flex}.frankie-root .grid{display:grid}.frankie-root .hidden{display:none}.frankie-root .inline{display:inline}.frankie-root .inline-flex{display:inline-flex}.frankie-root .table{display:table}.frankie-root .size-1{width:var(--spacing);height:var(--spacing)}.frankie-root .size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.frankie-root .size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.frankie-root .size-3\\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.frankie-root .size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.frankie-root .size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.frankie-root .size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.frankie-root .size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.frankie-root .size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.frankie-root .size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.frankie-root .size-full{width:100%;height:100%}.frankie-root .h-8{height:calc(var(--spacing) * 8)}.frankie-root .h-9{height:calc(var(--spacing) * 9)}.frankie-root .h-10{height:calc(var(--spacing) * 10)}.frankie-root .h-\\[32rem\\]{height:32rem}.frankie-root .h-full{height:100%}.frankie-root .h-px{height:1px}.frankie-root .min-h-7{min-height:calc(var(--spacing) * 7)}.frankie-root .min-h-\\[2\\.25rem\\]{min-height:2.25rem}.frankie-root .min-h-screen{min-height:100vh}.frankie-root .w-\\[22rem\\]{width:22rem}.frankie-root .w-full{width:100%}.frankie-root .max-w-\\[12rem\\]{max-width:12rem}.frankie-root .max-w-\\[14rem\\]{max-width:14rem}.frankie-root .max-w-\\[85\\%\\]{max-width:85%}.frankie-root .max-w-\\[calc\\(100vw-2rem\\)\\]{max-width:calc(100vw - 2rem)}.frankie-root .min-w-0{min-width:0}.frankie-root .flex-1{flex:1}.frankie-root .shrink-0{flex-shrink:0}.frankie-root .grow{flex-grow:1}.frankie-root .animate-pulse{animation:var(--animate-pulse)}.frankie-root .animate-spin{animation:var(--animate-spin)}.frankie-root .cursor-pointer{cursor:pointer}.frankie-root .resize{resize:both}.frankie-root .resize-none{resize:none}.frankie-root .list-none{list-style-type:none}.frankie-root .flex-col{flex-direction:column}.frankie-root .flex-wrap{flex-wrap:wrap}.frankie-root .items-center{align-items:center}.frankie-root .items-end{align-items:flex-end}.frankie-root .items-start{align-items:flex-start}.frankie-root .justify-center{justify-content:center}.frankie-root .justify-end{justify-content:flex-end}.frankie-root .gap-1{gap:var(--spacing)}.frankie-root .gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.frankie-root .gap-2{gap:calc(var(--spacing) * 2)}.frankie-root .gap-3{gap:calc(var(--spacing) * 3)}.frankie-root .gap-4{gap:calc(var(--spacing) * 4)}.frankie-root .truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.frankie-root .overflow-hidden{overflow:hidden}.frankie-root .overflow-y-auto{overflow-y:auto}.frankie-root .overscroll-contain{overscroll-behavior:contain}.frankie-root .rounded{border-radius:.25rem}.frankie-root .rounded-\\[calc\\(var\\(--frankie-radius\\)\\+4px\\)\\]{border-radius:calc(var(--frankie-radius) + 4px)}.frankie-root .rounded-\\[calc\\(var\\(--frankie-radius\\)-2px\\)\\]{border-radius:calc(var(--frankie-radius) - 2px)}.frankie-root .rounded-\\[var\\(--frankie-radius\\)\\]{border-radius:var(--frankie-radius)}.frankie-root .rounded-full{border-radius:3.40282e38px}.frankie-root .rounded-md{border-radius:var(--radius-md)}.frankie-root .rounded-none{border-radius:0}.frankie-root .border{border-style:var(--tw-border-style);border-width:1px}.frankie-root .border-0{border-style:var(--tw-border-style);border-width:0}.frankie-root .border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.frankie-root .border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.frankie-root .border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.frankie-root .border-border{border-color:var(--frankie-border)}.frankie-root .border-transparent{border-color:#0000}.frankie-root .bg-background{background-color:var(--frankie-background)}.frankie-root .bg-border{background-color:var(--frankie-border)}.frankie-root .bg-emerald-500{background-color:var(--color-emerald-500)}.frankie-root .bg-emerald-500\\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.frankie-root .bg-emerald-500\\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.frankie-root .bg-muted{background-color:var(--frankie-muted)}.frankie-root .bg-muted-foreground{background-color:var(--frankie-muted-foreground)}.frankie-root .bg-primary{background-color:var(--frankie-primary)}.frankie-root .bg-red-500{background-color:var(--color-red-500)}.frankie-root .bg-red-500\\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.frankie-root .bg-red-500\\/10{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.frankie-root .bg-secondary{background-color:var(--frankie-secondary)}.frankie-root .object-cover{object-fit:cover}.frankie-root .p-3{padding:calc(var(--spacing) * 3)}.frankie-root .p-4{padding:calc(var(--spacing) * 4)}.frankie-root .px-1{padding-inline:var(--spacing)}.frankie-root .px-2{padding-inline:calc(var(--spacing) * 2)}.frankie-root .px-3{padding-inline:calc(var(--spacing) * 3)}.frankie-root .px-4{padding-inline:calc(var(--spacing) * 4)}.frankie-root .px-6{padding-inline:calc(var(--spacing) * 6)}.frankie-root .py-0{padding-block:0}.frankie-root .py-0\\.5{padding-block:calc(var(--spacing) * .5)}.frankie-root .py-1{padding-block:var(--spacing)}.frankie-root .py-2{padding-block:calc(var(--spacing) * 2)}.frankie-root .py-3{padding-block:calc(var(--spacing) * 3)}.frankie-root .pl-2{padding-left:calc(var(--spacing) * 2)}.frankie-root .text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.frankie-root .text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.frankie-root .text-\\[0\\.625rem\\]{font-size:.625rem}.frankie-root .text-\\[0\\.6875rem\\]{font-size:.6875rem}.frankie-root .text-\\[11px\\]{font-size:11px}.frankie-root .leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.frankie-root .font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.frankie-root .font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.frankie-root .whitespace-nowrap{white-space:nowrap}.frankie-root .text-emerald-600{color:var(--color-emerald-600)}.frankie-root .text-foreground{color:var(--frankie-foreground)}.frankie-root .text-muted-foreground{color:var(--frankie-muted-foreground)}.frankie-root .text-primary{color:var(--frankie-primary)}.frankie-root .text-primary-foreground{color:var(--frankie-primary-foreground)}.frankie-root .text-red-600{color:var(--color-red-600)}.frankie-root .text-secondary-foreground{color:var(--frankie-secondary-foreground)}.frankie-root .italic{font-style:italic}.frankie-root .underline-offset-4{text-underline-offset:4px}.frankie-root .opacity-60{opacity:.6}.frankie-root .opacity-70{opacity:.7}.frankie-root .shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.frankie-root .outline{outline-style:var(--tw-outline-style);outline-width:1px}.frankie-root .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))}.frankie-root .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))}.frankie-root .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))}.frankie-root .ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.frankie-root .select-all{-webkit-user-select:all;user-select:all}.frankie-root .placeholder\\:text-muted-foreground::placeholder{color:var(--frankie-muted-foreground)}@media (hover:hover){.frankie-root .hover\\:border-border:hover{border-color:var(--frankie-border)}.frankie-root .hover\\:bg-muted:hover{background-color:var(--frankie-muted)}.frankie-root .hover\\:text-foreground:hover{color:var(--frankie-foreground)}.frankie-root .hover\\:underline:hover{text-decoration-line:underline}.frankie-root .hover\\:opacity-90:hover{opacity:.9}.frankie-root .hover\\:opacity-100:hover{opacity:1}}.frankie-root .focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + 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)}.frankie-root .focus-visible\\:ring-primary:focus-visible{--tw-ring-color:var(--frankie-primary)}.frankie-root .focus-visible\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.frankie-root .disabled\\:pointer-events-none:disabled{pointer-events:none}.frankie-root .disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.frankie-root .disabled\\:opacity-50:disabled{opacity:.5}.frankie-root .dark\\:text-emerald-400:where(.dark,.dark *){color:var(--color-emerald-400)}.frankie-root .dark\\:text-red-400:where(.dark,.dark *){color:var(--color-red-400)}.frankie-root .\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.frankie-root .\\[\\&_svg\\]\\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.frankie-root .\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.frankie-root .\\[\\&\\:\\:-webkit-details-marker\\]\\:hidden::-webkit-details-marker{display:none}.frankie-root.frankie-chat-panel{min-height:0;position:relative}.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px var(--frankie-primary), 0 12px 28px -12px #0f172a47, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel{box-shadow:0 32px 72px -18px color-mix(in srgb, var(--frankie-primary) 22%, #0f172a6b), 0 12px 28px -12px #0f172a47, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 8%, transparent)}}.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-widget-panel.dark{box-shadow:0 34px 80px -16px #000000b8, 0 14px 32px -12px #0009, 0 0 0 1px color-mix(in srgb, var(--frankie-foreground) 12%, transparent)}}.frankie-root .frankie-agent-context-wrap{flex:none;justify-content:center;padding:12px 10px;display:flex}.frankie-root .frankie-agent-context{max-width:100%;color:var(--frankie-foreground);font-size:13px;position:relative}.frankie-root .frankie-agent-context>summary{border:1px solid var(--frankie-border);background:var(--frankie-background);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:10px;min-height:44px;padding:7px 13px;list-style:none;display:flex;box-shadow:0 1px 3px #0000000d}.frankie-root .frankie-agent-context>summary::-webkit-details-marker{display:none}.frankie-root .frankie-agent-context>summary>svg{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-context-count{background:var(--frankie-muted);color:var(--frankie-muted-foreground);border-radius:999px;padding:2px 10px;font-size:12px}.frankie-root .frankie-context-status{color:var(--frankie-muted-foreground);align-items:center;gap:6px;font-size:12px;display:flex}.frankie-root .frankie-context-status i{background:currentColor;border-radius:50%;width:7px;height:7px}.frankie-root .frankie-context-status[data-active=true]{color:#00976b}.frankie-root .frankie-context-detail{z-index:10;border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:16px;width:340px;max-width:calc(100vw - 32px);padding:18px;position:absolute;top:calc(100% + 10px);left:50%;transform:translate(-50%);box-shadow:0 12px 32px #00000016}.frankie-root .frankie-context-detail p{color:var(--frankie-muted-foreground);margin:10px 0 0;font-size:12px;line-height:1.6}.frankie-root .frankie-context-detail ul{max-height:220px;margin:12px 0;padding:0;list-style:none;overflow:auto}.frankie-root .frankie-context-detail li{border-bottom:1px solid var(--frankie-border);overflow-wrap:anywhere;justify-content:space-between;gap:12px;padding:8px 0;display:flex}.frankie-root .frankie-context-detail small{color:var(--frankie-muted-foreground);flex:none}.frankie-root .frankie-sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.frankie-root.frankie-chat-panel-fill{--frankie-canvas:var(--frankie-background)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill{--frankie-canvas:color-mix(in srgb,var(--frankie-background) 60%,var(--frankie-muted))}}.frankie-root.frankie-chat-panel-fill{background:var(--frankie-canvas)}.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:44px 16px 26px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:14px max(24px,50% - 480px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-message-list{gap:38px}.frankie-root.frankie-chat-panel-fill .frankie-user-bubble{background:var(--frankie-muted);color:var(--frankie-foreground);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:24px;padding:12px 20px;font-size:15px}.frankie-root.frankie-chat-panel-fill .frankie-assistant-content{flex:1;max-width:100%;font-size:15px;line-height:1.7}.frankie-root.frankie-chat-panel-fill .frankie-assistant-message{gap:14px}.frankie-root .frankie-thinking{color:var(--frankie-muted-foreground);gap:5px}.frankie-root .frankie-thinking-label{margin-right:6px;font-size:14px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{background:0 0;border:0;flex:none;padding:16px max(24px,50% - 500px) 24px}.frankie-root.frankie-chat-panel-fill .frankie-composer{border:1px solid var(--frankie-border);background:var(--frankie-background);border-radius:28px;padding:14px;box-shadow:0 2px 4px #0000000a}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:var(--frankie-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{border-color:color-mix(in srgb,var(--frankie-foreground) 32%,var(--frankie-border))}}.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root.frankie-chat-panel-fill .frankie-composer:focus-within{box-shadow:0 0 0 2px color-mix(in srgb,var(--frankie-primary) 8%,transparent)}}.frankie-root.frankie-chat-panel-fill .frankie-composer-controls{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.frankie-root.frankie-chat-panel-fill .frankie-composer textarea{resize:none;width:100%;min-height:32px;max-height:140px;color:var(--frankie-foreground);box-shadow:none;background:0 0;border:0;border-radius:0;outline:none;flex:0 0 100%;order:-1;margin-bottom:4px;padding:2px 6px;font-size:16px}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Send],.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Stop]{background:var(--frankie-primary);width:42px;height:42px;color:var(--frankie-primary-foreground);border:0;border-radius:50%;margin-left:auto}.frankie-root.frankie-chat-panel-fill .frankie-composer button[aria-label=Attach\\ files]{border-radius:50%;width:42px;height:42px}.frankie-root .frankie-composer-actions{align-items:center;gap:6px;min-width:0;display:flex}.frankie-root .frankie-composer-meta{align-items:center;gap:8px;margin-top:6px;padding:0 2px;display:flex}.frankie-root .frankie-model-picker{align-items:center;min-width:0;display:inline-flex}.frankie-root .frankie-model-select{appearance:none;max-width:12rem;color:var(--frankie-muted-foreground);font:inherit;cursor:pointer;text-overflow:ellipsis;background-color:#0000;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238b8b8b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");background-position:right 6px center;background-repeat:no-repeat;background-size:11px;border:0;border-radius:8px;padding:5px 22px 5px 8px;font-size:12px;font-weight:500;line-height:1;transition:background-color .12s,color .12s}.frankie-root .frankie-model-select:hover{background-color:var(--frankie-muted);color:var(--frankie-foreground)}.frankie-root .frankie-model-select:disabled{opacity:.5;cursor:not-allowed}.frankie-root .frankie-model-select option{color:var(--frankie-foreground);background:var(--frankie-background);font-weight:400}.frankie-root .frankie-history-desktop{background:var(--frankie-background);width:290px;padding:20px 12px}.frankie-root .frankie-history-collapsed{width:56px;padding:20px 8px}.frankie-root .frankie-new-chat{background:0 0;border:0;justify-content:flex-start;padding:8px 12px;font-size:15px}.frankie-root .frankie-history-heading{color:var(--frankie-muted-foreground);padding:0 12px;font-size:12px;font-weight:400}.frankie-root .frankie-history-list button{min-height:44px;padding:10px 12px}.frankie-root .frankie-history-list button span{font-size:14px}.frankie-root .frankie-history-list button[aria-current],.frankie-root .frankie-history-list button:hover{background:var(--frankie-muted);border-color:#0000}.frankie-root .frankie-history-list small{display:none}.frankie-root .frankie-history-group{flex-direction:column;gap:2px;display:flex}.frankie-root .frankie-history-group+.frankie-history-group{margin-top:12px}.frankie-root .frankie-history-group-label{letter-spacing:.04em;color:var(--frankie-muted-foreground);margin:0;padding:4px 12px;font-size:11px;font-weight:600}.frankie-root .frankie-page-header{background:var(--frankie-background);height:56px;min-height:56px}.frankie-root .frankie-page-header>div{min-width:0}.frankie-root .frankie-thread-title{text-overflow:ellipsis;white-space:nowrap;max-width:55vw;font-weight:500;overflow:hidden}.frankie-root .frankie-page-header button{background:0 0;border-color:#0000}.frankie-root .frankie-page-canvas>.frankie-inline{max-width:none}@media (max-width:760px){.frankie-root.frankie-chat-panel-fill .frankie-agent-context-wrap{padding:20px 8px 14px}.frankie-root.frankie-chat-panel-fill .frankie-transcript{padding:12px 16px 16px}.frankie-root.frankie-chat-panel-fill .frankie-composer-footer{padding:10px 12px calc(12px + env(safe-area-inset-bottom))}.frankie-root .frankie-agent-context>summary{gap:6px;padding:7px 9px;font-size:12px}.frankie-root .frankie-context-count{padding:2px 7px;font-size:11px}.frankie-root .frankie-context-status{gap:4px;font-size:11px}.frankie-root .frankie-agent-context>summary>svg{width:14px}.frankie-root .frankie-thread-title{max-width:42vw}}.frankie-root .frankie-agent-context>summary>svg:first-child{box-sizing:content-box;background:var(--frankie-muted);border-radius:50%;padding:4px}.frankie-root.frankie-chat-panel-fill .frankie-agent-context>summary{font-size:14px}.frankie-root .frankie-agent-context>summary>span:first-of-type{border-right:1px solid var(--frankie-border);padding-right:10px}@media (max-width:760px){.frankie-root .frankie-page-header button>span{display:none}}.frankie-root .frankie-choices{flex-direction:column;gap:8px;margin-top:12px;display:flex}.frankie-root .frankie-choice{text-align:left;cursor:pointer;border:1px solid var(--frankie-border);border-radius:var(--frankie-radius);background:var(--frankie-background);width:100%;color:var(--frankie-foreground);font:inherit;align-items:center;gap:12px;padding:11px 14px;font-size:14px;line-height:1.4;transition:border-color .15s,background-color .15s,transform .12s;display:flex}.frankie-root .frankie-choice:hover:not(:disabled){border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){border-color:color-mix(in srgb, var(--frankie-primary) 55%, var(--frankie-border))}}.frankie-root .frankie-choice:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 6%, var(--frankie-background))}}.frankie-root .frankie-choice:active:not(:disabled){transform:scale(.99)}.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px var(--frankie-primary);outline:none}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-choice:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, var(--frankie-primary) 40%, transparent)}}.frankie-root .frankie-choice:disabled{opacity:.6;cursor:default}.frankie-root .frankie-choice-index{border:1px solid var(--frankie-border);background:var(--frankie-muted);width:24px;height:24px;color:var(--frankie-muted-foreground);border-radius:50%;flex:none;place-items:center;font-size:12px;font-weight:600;transition:background-color .15s,color .15s,border-color .15s;display:grid}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-primary);border-color:var(--frankie-primary);color:var(--frankie-primary-foreground)}.frankie-root .frankie-choice-label{flex:1;min-width:0}.frankie-root .frankie-choice-go{color:var(--frankie-muted-foreground);opacity:0;flex:none;transition:opacity .15s,transform .15s;transform:translate(-4px)}.frankie-root .frankie-choice:hover:not(:disabled) .frankie-choice-go{opacity:1;color:var(--frankie-primary);transform:none}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-choice,.frankie-root .frankie-choice-go,.frankie-root .frankie-choice-index{transition:none}}.frankie-root .frankie-choice-other{color:var(--frankie-muted-foreground);border-style:dashed}.frankie-root .frankie-choice-other .frankie-choice-index{background:0 0}.frankie-root .frankie-choice-other:hover:not(:disabled){color:var(--frankie-foreground)}.frankie-root .frankie-choice-other:hover:not(:disabled) .frankie-choice-index{background:var(--frankie-muted);border-color:var(--frankie-border);color:var(--frankie-foreground)}.frankie-root .frankie-choice-hint{color:var(--frankie-muted-foreground);flex:none;font-size:12px}.frankie-root .frankie-skeleton{flex-direction:column;gap:8px;max-width:min(420px,100%);padding:4px 0 6px;display:flex}.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, var(--frankie-muted-foreground) 25%, var(--frankie-muted-foreground) 37%, var(--frankie-muted-foreground) 63%);border-radius:6px;height:12px}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:linear-gradient(90deg, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 25%, color-mix(in srgb, var(--frankie-muted-foreground) 19%, transparent) 37%, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 63%)}}.frankie-root .frankie-skeleton-line{background-size:400% 100%;animation:2.2s ease-in-out infinite frankie-shimmer}.frankie-root .frankie-skeleton.is-delayed{animation:.25s .35s both frankie-skeleton-in}@keyframes frankie-skeleton-in{0%{opacity:0}to{opacity:1}}@keyframes frankie-shimmer{0%{background-position:100%}to{background-position:0}}@keyframes frankie-skeleton-pulse{0%,to{opacity:.45}50%{opacity:.85}}@media (prefers-reduced-motion:reduce){.frankie-root .frankie-skeleton-line{background:var(--frankie-muted-foreground)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-skeleton-line{background:color-mix(in srgb, var(--frankie-muted-foreground) 16%, transparent)}}.frankie-root .frankie-skeleton-line{animation:1.6s ease-in-out infinite frankie-skeleton-pulse}}.frankie-root:not(.frankie-chat-panel-fill) .frankie-composer-controls:has(.frankie-composer-actions>:not(input[hidden])){flex-wrap:wrap;align-items:center;row-gap:8px}.frankie-root:not(.frankie-chat-panel-fill) .frankie-composer-controls:has(.frankie-composer-actions>:not(input[hidden]))>textarea{flex:1 0 100%;order:-1;width:100%}.frankie-root:not(.frankie-chat-panel-fill) .frankie-composer-controls:has(.frankie-composer-actions>:not(input[hidden]))>.frankie-composer-actions{flex:auto}.frankie-root:not(.frankie-chat-panel-fill) .frankie-composer-controls:has(.frankie-composer-actions>:not(input[hidden]))>button{margin-left:auto}.frankie-root .frankie-action{border:1px solid var(--frankie-border);border-radius:var(--frankie-radius);background:var(--frankie-background);color:var(--frankie-foreground);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;font-size:14px;line-height:1.4;display:flex}.frankie-root .frankie-action.is-pending{border-color:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-action.is-pending{border-color:color-mix(in srgb, var(--frankie-primary) 45%, var(--frankie-border))}}.frankie-root .frankie-action.is-pending{background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-action.is-pending{background:color-mix(in srgb, var(--frankie-primary) 5%, var(--frankie-background))}}.frankie-root .frankie-action-head{align-items:flex-start;gap:10px;display:flex}.frankie-root .frankie-action-icon{color:var(--frankie-primary);flex-shrink:0;margin-top:2px}.frankie-root .frankie-action-title{flex-direction:column;gap:2px;min-width:0;display:flex}.frankie-root .frankie-action-title strong{overflow-wrap:anywhere;font-weight:600}.frankie-root .frankie-action-title span{color:var(--frankie-muted-foreground);font-size:12px}.frankie-root .frankie-action-route{border-radius:calc(var(--frankie-radius) * .6);background:var(--frankie-muted);overflow-wrap:anywhere;padding:6px 8px;font-size:12px;display:block}.frankie-root .frankie-action-route span{font-weight:600}.frankie-root .frankie-action-fields{gap:6px;margin:0;display:grid}.frankie-root .frankie-action-fields>div{grid-template-columns:minmax(0,35%) minmax(0,1fr);gap:10px;display:grid}.frankie-root .frankie-action-fields dt{color:var(--frankie-muted-foreground);overflow-wrap:anywhere;font-size:12px}.frankie-root .frankie-action-fields dd{white-space:pre-wrap;overflow-wrap:anywhere;max-height:8.5em;margin:0;font-size:13px;overflow:auto}.frankie-root .frankie-action-buttons{flex-wrap:wrap;gap:8px;display:flex}.frankie-root .frankie-action-buttons button{cursor:pointer;font:inherit;border-radius:var(--frankie-radius);border:1px solid var(--frankie-border);align-items:center;gap:6px;padding:7px 14px;font-size:14px;font-weight:500;transition:background-color .15s,border-color .15s;display:inline-flex}.frankie-root .frankie-action-approve{background:var(--frankie-primary);color:var(--frankie-primary-foreground);border-color:var(--frankie-primary)}.frankie-root .frankie-action-approve:hover:not(:disabled){background:var(--frankie-primary)}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-action-approve:hover:not(:disabled){background:color-mix(in srgb, var(--frankie-primary) 88%, black)}}.frankie-root .frankie-action-cancel{background:var(--frankie-background);color:var(--frankie-foreground)}.frankie-root .frankie-action-cancel:hover:not(:disabled){background:var(--frankie-muted)}.frankie-root .frankie-action-buttons button:disabled{opacity:.55;cursor:not-allowed}.frankie-root .frankie-action-buttons button:focus-visible{box-shadow:0 0 0 2px var(--frankie-primary);outline:none}@supports (color:color-mix(in lab, red, red)){.frankie-root .frankie-action-buttons button:focus-visible{box-shadow:0 0 0 2px color-mix(in srgb, var(--frankie-primary) 40%, transparent)}}@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-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-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}`;
1032
1073
 
1033
1074
  // src/lib/ensure-frankie-styles.ts
1034
1075
  var STYLE_ELEMENT_ID = "frankie-fallback-styles";
@@ -1102,8 +1143,8 @@ function bottomObstruction(root, position, offset) {
1102
1143
  seen.add(bar);
1103
1144
  const rect = bar.getBoundingClientRect();
1104
1145
  const anchoredToBottom = rect.bottom >= height - 4;
1105
- const short = rect.height > 0 && rect.height < height * 0.4;
1106
- if (anchoredToBottom && short) lift = Math.max(lift, height - rect.top);
1146
+ const short2 = rect.height > 0 && rect.height < height * 0.4;
1147
+ if (anchoredToBottom && short2) lift = Math.max(lift, height - rect.top);
1107
1148
  }
1108
1149
  }
1109
1150
  return Math.round(lift);
@@ -1189,7 +1230,7 @@ function Button({ className, variant, size, asChild = false, ...props }) {
1189
1230
  }
1190
1231
 
1191
1232
  // src/components/chat/ChatPanel.tsx
1192
- var import_lucide_react7 = require("lucide-react");
1233
+ var import_lucide_react8 = require("lucide-react");
1193
1234
  var import_react10 = require("react");
1194
1235
 
1195
1236
  // src/components/ui/avatar.tsx
@@ -1565,7 +1606,7 @@ function readAsBase64(file) {
1565
1606
  }
1566
1607
 
1567
1608
  // src/components/chat/MessageBubble.tsx
1568
- var import_lucide_react6 = require("lucide-react");
1609
+ var import_lucide_react7 = require("lucide-react");
1569
1610
  var import_react9 = require("react");
1570
1611
 
1571
1612
  // src/lib/choices.ts
@@ -1586,9 +1627,68 @@ function parseOptionLines(block) {
1586
1627
  return block.split("\n").map((line) => line.trim().replace(/^([-*+]|\d+[.)])\s+/, "").trim()).filter(Boolean);
1587
1628
  }
1588
1629
 
1589
- // src/components/chat/Choices.tsx
1630
+ // src/components/chat/ActionConfirm.tsx
1590
1631
  var import_lucide_react4 = require("lucide-react");
1591
1632
  var import_jsx_runtime10 = require("react/jsx-runtime");
1633
+ function ActionConfirm({
1634
+ action,
1635
+ onAnswer,
1636
+ disabled,
1637
+ live
1638
+ }) {
1639
+ const pending = action.state === "pending";
1640
+ const fields = inputFields(action.preview.input);
1641
+ const status = pending ? live ? void 0 : "Not run" : action.state === "approved" ? "Approved" : "Cancelled";
1642
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "frankie-action" + (pending && live ? " is-pending" : ""), role: "group", "aria-label": `Approve: ${action.label}`, children: [
1643
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "frankie-action-head", children: [
1644
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ShieldAlert, { className: "frankie-action-icon size-4", "aria-hidden": true }),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "frankie-action-title", children: [
1646
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: action.label }),
1647
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: pending && live ? "Needs your approval before it runs" : status })
1648
+ ] })
1649
+ ] }),
1650
+ action.preview.method && action.preview.path ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("code", { className: "frankie-action-route", children: [
1651
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: action.preview.method }),
1652
+ " ",
1653
+ action.preview.path
1654
+ ] }) : null,
1655
+ fields.length ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dl", { className: "frankie-action-fields", children: fields.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1656
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: key }),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: value })
1658
+ ] }, key)) }) : null,
1659
+ pending && live && onAnswer ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "frankie-action-buttons", children: [
1660
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: "frankie-action-approve", disabled, onClick: () => onAnswer(action.toolUseId, true), children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Check, { className: "size-4", "aria-hidden": true }),
1662
+ " Approve"
1663
+ ] }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: "frankie-action-cancel", disabled, onClick: () => onAnswer(action.toolUseId, false), children: [
1665
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "size-4", "aria-hidden": true }),
1666
+ " Cancel"
1667
+ ] })
1668
+ ] }) : null
1669
+ ] });
1670
+ }
1671
+ function inputFields(input) {
1672
+ if (input === void 0 || input === null) return [];
1673
+ if (typeof input !== "object" || Array.isArray(input)) return [["input", short(input)]];
1674
+ const rows = [];
1675
+ for (const [key, value] of Object.entries(input)) {
1676
+ if (value === void 0) continue;
1677
+ if (key === "body" && value && typeof value === "object" && !Array.isArray(value)) {
1678
+ for (const [field, inner] of Object.entries(value)) rows.push([field, short(inner)]);
1679
+ continue;
1680
+ }
1681
+ rows.push([key, short(value)]);
1682
+ }
1683
+ return rows;
1684
+ }
1685
+ function short(value) {
1686
+ return typeof value === "string" ? value : JSON.stringify(value, null, 1);
1687
+ }
1688
+
1689
+ // src/components/chat/Choices.tsx
1690
+ var import_lucide_react5 = require("lucide-react");
1691
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1592
1692
  function Choices({
1593
1693
  options,
1594
1694
  onPick,
@@ -1596,8 +1696,8 @@ function Choices({
1596
1696
  disabled
1597
1697
  }) {
1598
1698
  if (options.length === 0) return null;
1599
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "frankie-choices", role: "group", "aria-label": "Choose an option", children: [
1600
- options.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1699
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "frankie-choices", role: "group", "aria-label": "Choose an option", children: [
1700
+ options.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1601
1701
  "button",
1602
1702
  {
1603
1703
  type: "button",
@@ -1605,14 +1705,14 @@ function Choices({
1605
1705
  disabled,
1606
1706
  onClick: () => onPick(option),
1607
1707
  children: [
1608
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "frankie-choice-index", "aria-hidden": true, children: index + 1 }),
1609
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "frankie-choice-label", children: option }),
1610
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ArrowRight, { className: "frankie-choice-go size-4", "aria-hidden": true })
1708
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "frankie-choice-index", "aria-hidden": true, children: index + 1 }),
1709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "frankie-choice-label", children: option }),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.ArrowRight, { className: "frankie-choice-go size-4", "aria-hidden": true })
1611
1711
  ]
1612
1712
  },
1613
1713
  `${index}-${option}`
1614
1714
  )),
1615
- onSomethingElse ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1715
+ onSomethingElse ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1616
1716
  "button",
1617
1717
  {
1618
1718
  type: "button",
@@ -1620,9 +1720,9 @@ function Choices({
1620
1720
  disabled,
1621
1721
  onClick: onSomethingElse,
1622
1722
  children: [
1623
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "frankie-choice-index", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.PencilLine, { className: "size-3.5" }) }),
1624
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "frankie-choice-label", children: "Something else\u2026" }),
1625
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "frankie-choice-hint", "aria-hidden": true, children: "Type your own" })
1723
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "frankie-choice-index", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.PencilLine, { className: "size-3.5" }) }),
1724
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "frankie-choice-label", children: "Something else\u2026" }),
1725
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "frankie-choice-hint", "aria-hidden": true, children: "Type your own" })
1626
1726
  ]
1627
1727
  }
1628
1728
  ) : null
@@ -1631,10 +1731,10 @@ function Choices({
1631
1731
 
1632
1732
  // src/components/chat/Markdown.tsx
1633
1733
  var import_react8 = require("react");
1634
- var import_jsx_runtime11 = require("react/jsx-runtime");
1734
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1635
1735
  var Markdown = (0, import_react8.memo)(function Markdown2({ text, className }) {
1636
1736
  const blocks = (0, import_react8.useMemo)(() => renderBlocks(text), [text]);
1637
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("frankie-prose", className), children: blocks });
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("frankie-prose", className), children: blocks });
1638
1738
  });
1639
1739
  function renderBlocks(text) {
1640
1740
  const lines = text.split("\n");
@@ -1644,13 +1744,13 @@ function renderBlocks(text) {
1644
1744
  let code = null;
1645
1745
  const flushParagraph = () => {
1646
1746
  if (paragraph.length === 0) return;
1647
- blocks.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { children: renderInline(paragraph.join(" ")) }, `p${blocks.length}`));
1747
+ blocks.push(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: renderInline(paragraph.join(" ")) }, `p${blocks.length}`));
1648
1748
  paragraph = [];
1649
1749
  };
1650
1750
  const flushList = () => {
1651
1751
  if (!list) return;
1652
- const items = list.items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: renderInline(item) }, index));
1653
- blocks.push(list.ordered ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ol", { children: items }, `l${blocks.length}`) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { children: items }, `l${blocks.length}`));
1752
+ const items = list.items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: renderInline(item) }, index));
1753
+ blocks.push(list.ordered ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ol", { children: items }, `l${blocks.length}`) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { children: items }, `l${blocks.length}`));
1654
1754
  list = null;
1655
1755
  };
1656
1756
  for (const line of lines) {
@@ -1658,7 +1758,7 @@ function renderBlocks(text) {
1658
1758
  if (fence) {
1659
1759
  if (code) {
1660
1760
  blocks.push(
1661
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: code.lines.join("\n") }) }, `c${blocks.length}`)
1761
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { children: code.lines.join("\n") }) }, `c${blocks.length}`)
1662
1762
  );
1663
1763
  code = null;
1664
1764
  } else {
@@ -1695,7 +1795,7 @@ function renderBlocks(text) {
1695
1795
  flushList();
1696
1796
  const level = (heading[1] ?? "#").length;
1697
1797
  const Tag = level <= 1 ? "h3" : level === 2 ? "h4" : "h5";
1698
- blocks.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Tag, { className: "frankie-h", children: renderInline(heading[2] ?? "") }, `h${blocks.length}`));
1798
+ blocks.push(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Tag, { className: "frankie-h", children: renderInline(heading[2] ?? "") }, `h${blocks.length}`));
1699
1799
  continue;
1700
1800
  }
1701
1801
  flushList();
@@ -1703,7 +1803,7 @@ function renderBlocks(text) {
1703
1803
  }
1704
1804
  if (code) {
1705
1805
  blocks.push(
1706
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: code.lines.join("\n") }) }, `c${blocks.length}`)
1806
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("pre", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { children: code.lines.join("\n") }) }, `c${blocks.length}`)
1707
1807
  );
1708
1808
  }
1709
1809
  flushParagraph();
@@ -1718,30 +1818,30 @@ function renderInline(text) {
1718
1818
  const token = match[0];
1719
1819
  const start = match.index;
1720
1820
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
1721
- nodes.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react8.Fragment, { children: renderToken(token) }, start));
1821
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react8.Fragment, { children: renderToken(token) }, start));
1722
1822
  lastIndex = start + token.length;
1723
1823
  }
1724
1824
  if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
1725
1825
  return nodes;
1726
1826
  }
1727
1827
  function renderToken(token) {
1728
- if (token.startsWith("**")) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: token.slice(2, -2) });
1729
- if (token.startsWith("*")) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("em", { children: token.slice(1, -1) });
1730
- if (token.startsWith("`")) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: token.slice(1, -1) });
1828
+ if (token.startsWith("**")) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: token.slice(2, -2) });
1829
+ if (token.startsWith("*")) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("em", { children: token.slice(1, -1) });
1830
+ if (token.startsWith("`")) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { children: token.slice(1, -1) });
1731
1831
  const link = /^\[([^\]]+)\]\(([^)]+)\)$/.exec(token);
1732
1832
  const href = link ? link[2] ?? "" : token;
1733
1833
  const label = link ? link[1] ?? "" : token;
1734
- if (!/^(https?:\/\/|\/)/.test(href)) return token;
1735
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer nofollow", children: label });
1834
+ if (!/^(https?:\/\/|\/(?![\/\\]))/.test(href)) return token;
1835
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer nofollow", children: label });
1736
1836
  }
1737
1837
 
1738
1838
  // src/components/chat/ToolActivityList.tsx
1739
- var import_lucide_react5 = require("lucide-react");
1839
+ var import_lucide_react6 = require("lucide-react");
1740
1840
  var import_core = require("@frankieai/core");
1741
1841
 
1742
1842
  // src/components/ui/badge.tsx
1743
1843
  var import_class_variance_authority2 = require("class-variance-authority");
1744
- var import_jsx_runtime12 = require("react/jsx-runtime");
1844
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1745
1845
  var badgeVariants = (0, import_class_variance_authority2.cva)(
1746
1846
  "inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[0.6875rem] font-medium",
1747
1847
  {
@@ -1761,46 +1861,46 @@ function Badge({
1761
1861
  variant,
1762
1862
  ...props
1763
1863
  }) {
1764
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: cn(badgeVariants({ variant }), className), ...props });
1864
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: cn(badgeVariants({ variant }), className), ...props });
1765
1865
  }
1766
1866
 
1767
1867
  // src/components/chat/ToolActivityList.tsx
1768
- var import_jsx_runtime13 = require("react/jsx-runtime");
1868
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1769
1869
  function ToolActivityList({ tools, renderTool }) {
1770
1870
  if (tools.length === 0) return null;
1771
1871
  const running = tools.some((tool) => tool.status === "running");
1772
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("details", { className: "frankie-tool-activity mt-2", open: running, children: [
1773
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("summary", { className: "inline-flex min-h-7 cursor-pointer list-none items-center gap-1.5 rounded-md px-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden", children: [
1774
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.ChevronDown, { className: "frankie-tool-chevron size-3.5 transition-transform", "aria-hidden": "true" }),
1775
- running ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.Loader2, { className: "size-3.5 animate-spin", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.Wrench, { className: "size-3.5", "aria-hidden": "true" }),
1776
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: running ? "Working" : "Activity" }),
1777
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-[11px]", children: [
1872
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("details", { className: "frankie-tool-activity mt-2", open: running, children: [
1873
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("summary", { className: "inline-flex min-h-7 cursor-pointer list-none items-center gap-1.5 rounded-md px-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden", children: [
1874
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.ChevronDown, { className: "frankie-tool-chevron size-3.5 transition-transform", "aria-hidden": "true" }),
1875
+ running ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Loader2, { className: "size-3.5 animate-spin", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Wrench, { className: "size-3.5", "aria-hidden": "true" }),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: running ? "Working" : "Activity" }),
1877
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "text-[11px]", children: [
1778
1878
  "\xB7 ",
1779
1879
  tools.length,
1780
1880
  " tool call",
1781
1881
  tools.length === 1 ? "" : "s"
1782
1882
  ] })
1783
1883
  ] }),
1784
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("ul", { className: "mt-1 flex flex-col gap-1 border-l border-border pl-2", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { children: renderTool ? renderTool(tool) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolActivityRow, { tool }) }, tool.id)) })
1884
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "mt-1 flex flex-col gap-1 border-l border-border pl-2", children: tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("li", { children: renderTool ? renderTool(tool) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolActivityRow, { tool }) }, tool.id)) })
1785
1885
  ] });
1786
1886
  }
1787
1887
  function ToolActivityRow({ tool }) {
1788
1888
  const isSkill = tool.name === import_core.SKILL_TOOL_NAME;
1789
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Badge, { variant: badgeVariant(tool.status), title: tool.detail ?? tool.name, children: [
1790
- isSkill && tool.status !== "running" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.Sparkles, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolIcon, { status: tool.status }),
1791
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate", children: tool.label })
1889
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Badge, { variant: badgeVariant(tool.status), title: tool.detail ?? tool.name, children: [
1890
+ isSkill && tool.status !== "running" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Sparkles, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolIcon, { status: tool.status }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate", children: tool.label })
1792
1892
  ] });
1793
1893
  }
1794
1894
  function ToolIcon({ status }) {
1795
1895
  switch (status) {
1796
1896
  case "running":
1797
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.Loader2, { className: "size-3 animate-spin", "aria-hidden": "true" });
1897
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Loader2, { className: "size-3 animate-spin", "aria-hidden": "true" });
1798
1898
  case "done":
1799
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.Check, { className: "size-3", "aria-hidden": "true" });
1899
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Check, { className: "size-3", "aria-hidden": "true" });
1800
1900
  case "denied":
1801
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.ShieldAlert, { className: "size-3", "aria-hidden": "true" });
1901
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.ShieldAlert, { className: "size-3", "aria-hidden": "true" });
1802
1902
  default:
1803
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.X, { className: "size-3", "aria-hidden": "true" });
1903
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.X, { className: "size-3", "aria-hidden": "true" });
1804
1904
  }
1805
1905
  }
1806
1906
  function badgeVariant(status) {
@@ -1811,7 +1911,7 @@ function badgeVariant(status) {
1811
1911
  }
1812
1912
 
1813
1913
  // src/components/chat/MessageBubble.tsx
1814
- var import_jsx_runtime14 = require("react/jsx-runtime");
1914
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1815
1915
  var MessageBubble = (0, import_react9.memo)(function MessageBubble2({
1816
1916
  message,
1817
1917
  assistantName,
@@ -1821,40 +1921,50 @@ var MessageBubble = (0, import_react9.memo)(function MessageBubble2({
1821
1921
  onChoose,
1822
1922
  onRequestInput,
1823
1923
  active,
1824
- busy
1924
+ busy,
1925
+ onAction
1825
1926
  }) {
1826
1927
  if (message.role === "user") {
1827
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-user-message flex flex-col items-end gap-1", children: [
1828
- message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex max-w-[85%] flex-wrap justify-end gap-1", children: message.attachments.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1928
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-user-message flex flex-col items-end gap-1", children: [
1929
+ message.attachments?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex max-w-[85%] flex-wrap justify-end gap-1", children: message.attachments.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1829
1930
  "span",
1830
1931
  {
1831
1932
  className: "inline-flex max-w-[12rem] items-center gap-1 rounded-[var(--frankie-radius)] border border-border bg-muted px-2 py-1 text-xs",
1832
1933
  children: [
1833
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Paperclip, { className: "size-3 shrink-0 opacity-70" }),
1834
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate", children: file.name })
1934
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react7.Paperclip, { className: "size-3 shrink-0 opacity-70" }),
1935
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate", children: file.name })
1835
1936
  ]
1836
1937
  },
1837
1938
  `${file.name}-${index}`
1838
1939
  )) }) : null,
1839
- message.text ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex max-w-[85%] items-end gap-1", children: [
1840
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "frankie-user-bubble rounded-[var(--frankie-radius)] bg-primary px-3 py-2 text-sm text-primary-foreground", children: message.text }),
1841
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageCopyButton, { text: message.text })
1940
+ message.text ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex max-w-[85%] items-end gap-1", children: [
1941
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "frankie-user-bubble rounded-[var(--frankie-radius)] bg-primary px-3 py-2 text-sm text-primary-foreground", children: message.text }),
1942
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageCopyButton, { text: message.text })
1842
1943
  ] }) : null
1843
1944
  ] });
1844
1945
  }
1845
1946
  const { body, options } = extractChoices(message.text);
1846
1947
  const showChoices = Boolean(active && onChoose && options && message.status === "done");
1847
1948
  const waiting = message.status === "streaming" && body.length === 0 && message.tools.length === 0;
1848
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-assistant-message flex gap-2", children: [
1849
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-assistant-actions mt-0.5 flex shrink-0 flex-col items-center gap-1", children: [
1850
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Avatar, { ...avatarUrl ? { src: avatarUrl } : {}, name: assistantName }),
1851
- body ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageCopyButton, { text: body }) : null
1949
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-assistant-message flex gap-2", children: [
1950
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-assistant-actions mt-0.5 flex shrink-0 flex-col items-center gap-1", children: [
1951
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Avatar, { ...avatarUrl ? { src: avatarUrl } : {}, name: assistantName }),
1952
+ body ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MessageCopyButton, { text: body }) : null
1852
1953
  ] }),
1853
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-assistant-content min-w-0 max-w-[85%]", children: [
1854
- message.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400", children: message.error }) : body ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Markdown, { text: body, className: "text-sm" }) : null,
1855
- showChoices ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Choices, { options: options ?? [], onPick: onChoose, ...onRequestInput ? { onSomethingElse: onRequestInput } : {}, disabled: busy }) : null,
1856
- showToolActivity ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolActivityList, { tools: message.tools, ...renderTool ? { renderTool } : {} }) : null,
1857
- waiting ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Thinking, { delayed: true }) : null
1954
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-assistant-content min-w-0 max-w-[85%]", children: [
1955
+ message.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "rounded-[var(--frankie-radius)] bg-red-500/10 px-3 py-2 text-sm text-red-600 dark:text-red-400", children: message.error }) : body ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Markdown, { text: body, className: "text-sm" }) : null,
1956
+ message.action ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1957
+ ActionConfirm,
1958
+ {
1959
+ action: message.action,
1960
+ live: Boolean(active),
1961
+ disabled: busy || message.status === "streaming",
1962
+ ...onAction ? { onAnswer: onAction } : {}
1963
+ }
1964
+ ) : null,
1965
+ showChoices ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Choices, { options: options ?? [], onPick: onChoose, ...onRequestInput ? { onSomethingElse: onRequestInput } : {}, disabled: busy }) : null,
1966
+ showToolActivity ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ToolActivityList, { tools: message.tools, ...renderTool ? { renderTool } : {} }) : null,
1967
+ waiting ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Thinking, { delayed: true }) : null
1858
1968
  ] })
1859
1969
  ] });
1860
1970
  });
@@ -1868,12 +1978,12 @@ function MessageCopyButton({ text }) {
1868
1978
  } catch {
1869
1979
  }
1870
1980
  };
1871
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", onClick: () => void copy(), className: "frankie-message-copy inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-transparent text-muted-foreground transition hover:border-border hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary", "aria-label": copied ? "Copied" : "Copy message", title: copied ? "Copied" : "Copy message", children: copied ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Check, { className: "size-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.Copy, { className: "size-3.5", "aria-hidden": "true" }) });
1981
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", onClick: () => void copy(), className: "frankie-message-copy inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-transparent text-muted-foreground transition hover:border-border hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary", "aria-label": copied ? "Copied" : "Copy message", title: copied ? "Copied" : "Copy message", children: copied ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react7.Check, { className: "size-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react7.Copy, { className: "size-3.5", "aria-hidden": "true" }) });
1872
1982
  }
1873
1983
  function TypingDots() {
1874
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "frankie-thinking inline-flex items-center gap-1 py-2", role: "status", "aria-label": "Thinking", children: [
1875
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-thinking-label", children: "Thinking" }),
1876
- [0, 1, 2].map((index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1984
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "frankie-thinking inline-flex items-center gap-1 py-2", role: "status", "aria-label": "Thinking", children: [
1985
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "frankie-thinking-label", children: "Thinking" }),
1986
+ [0, 1, 2].map((index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1877
1987
  "span",
1878
1988
  {
1879
1989
  className: cn("size-1.5 animate-pulse rounded-full bg-muted-foreground"),
@@ -1884,15 +1994,15 @@ function TypingDots() {
1884
1994
  ] });
1885
1995
  }
1886
1996
  function Thinking({ delayed = false }) {
1887
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-skeleton" + (delayed ? " is-delayed" : ""), role: "status", "aria-label": "Thinking", children: [
1888
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "62%" } }),
1889
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "92%" } }),
1890
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "48%" } })
1997
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-skeleton" + (delayed ? " is-delayed" : ""), role: "status", "aria-label": "Thinking", children: [
1998
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "frankie-skeleton-line", style: { width: "62%" } }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "frankie-skeleton-line", style: { width: "92%" } }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "frankie-skeleton-line", style: { width: "48%" } })
1891
2001
  ] });
1892
2002
  }
1893
2003
 
1894
2004
  // src/components/chat/ChatPanel.tsx
1895
- var import_jsx_runtime15 = require("react/jsx-runtime");
2005
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1896
2006
  function ChatPanel({
1897
2007
  className,
1898
2008
  header,
@@ -1907,7 +2017,7 @@ function ChatPanel({
1907
2017
  }) {
1908
2018
  const { config, configError, loading } = useFrankie();
1909
2019
  const theme = useFrankieTheme();
1910
- const { messages, busy, restoring, error, send, stop, reset } = useFrankieChat();
2020
+ const { messages, busy, restoring, error, send, answerAction, stop, reset } = useFrankieChat();
1911
2021
  const scrollRef = (0, import_react10.useRef)(null);
1912
2022
  const atBottomRef = (0, import_react10.useRef)(true);
1913
2023
  const features = config?.features;
@@ -1936,7 +2046,7 @@ function ChatPanel({
1936
2046
  }, [messages]);
1937
2047
  const name = config?.branding.name ?? "Assistant";
1938
2048
  const mode = useResolvedMode(theme?.mode);
1939
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2049
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1940
2050
  Card,
1941
2051
  {
1942
2052
  className: cn(
@@ -1949,22 +2059,22 @@ function ChatPanel({
1949
2059
  style: themeToCssVars(theme),
1950
2060
  "data-frankie-mode": mode,
1951
2061
  children: [
1952
- header === false ? null : header !== void 0 ? header : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(CardHeader, { children: [
1953
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Avatar, { ...config?.branding.avatarUrl ? { src: config.branding.avatarUrl } : {}, name }),
1954
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "min-w-0 flex-1", children: [
1955
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CardTitle, { children: name }),
1956
- config?.branding.tagline ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CardDescription, { children: config.branding.tagline }) : null
2062
+ header === false ? null : header !== void 0 ? header : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(CardHeader, { children: [
2063
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Avatar, { ...config?.branding.avatarUrl ? { src: config.branding.avatarUrl } : {}, name }),
2064
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "min-w-0 flex-1", children: [
2065
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CardTitle, { children: name }),
2066
+ config?.branding.tagline ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CardDescription, { children: config.branding.tagline }) : null
1957
2067
  ] }),
1958
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: "icon", variant: "ghost", onClick: reset, "aria-label": "Start a new conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react7.RotateCcw, {}) }),
1959
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Button, { size: "icon", variant: "ghost", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react7.X, {}) }) : null
2068
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Button, { size: "icon", variant: "ghost", onClick: reset, "aria-label": "Start a new conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.RotateCcw, {}) }),
2069
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Button, { size: "icon", variant: "ghost", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.X, {}) }) : null
1960
2070
  ] }),
1961
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AgentContext, {}),
1962
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CardContent, { className: "frankie-conversation-content", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ScrollArea, { ref: scrollRef, className: "frankie-transcript flex h-full flex-col gap-4 p-4", "aria-live": "polite", children: configError ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "frankie-config-error", role: "alert", children: [
1963
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: "Frankie couldn\u2019t start" }),
1964
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: configError }),
1965
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: "Refresh this page after checking the workspace\u2019s allowed origin and sign-in settings." })
1966
- ] }) : loading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Starting Frankie\u2026" }) : messages.length === 0 ? emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ChatEmptyState, {}) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "frankie-message-list flex flex-col gap-4", children: messages.map(
1967
- (message, index) => renderMessage ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { children: renderMessage(message) }, message.id) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2071
+ config?.agentContext === false ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AgentContext, {}),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CardContent, { className: "frankie-conversation-content", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ScrollArea, { ref: scrollRef, className: "frankie-transcript flex h-full flex-col gap-4 p-4", "aria-live": "polite", children: configError ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "frankie-config-error", role: "alert", children: [
2073
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: "Frankie couldn\u2019t start" }),
2074
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: configError }),
2075
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: "Refresh this page after checking the workspace\u2019s allowed origin and sign-in settings." })
2076
+ ] }) : loading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-sm text-muted-foreground", children: "Starting Frankie\u2026" }) : messages.length === 0 ? emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatEmptyState, {}) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "frankie-message-list flex flex-col gap-4", children: messages.map(
2077
+ (message, index) => renderMessage ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children: renderMessage(message) }, message.id) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1968
2078
  MessageBubble,
1969
2079
  {
1970
2080
  message,
@@ -1975,14 +2085,15 @@ function ChatPanel({
1975
2085
  onChoose: send,
1976
2086
  onRequestInput: focusComposer,
1977
2087
  active: index === messages.length - 1,
1978
- busy
2088
+ busy,
2089
+ onAction: (toolUseId, approved) => void answerAction(toolUseId, approved)
1979
2090
  },
1980
2091
  message.id
1981
2092
  )
1982
2093
  ) }) }) }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(CardFooter, { className: "frankie-composer-footer flex flex-col gap-2", children: [
1984
- error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "w-full text-xs text-red-600 dark:text-red-400", children: error }) : null,
1985
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2094
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(CardFooter, { className: "frankie-composer-footer flex flex-col gap-2", children: [
2095
+ error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "w-full text-xs text-red-600 dark:text-red-400", children: error }) : null,
2096
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1986
2097
  Composer,
1987
2098
  {
1988
2099
  onSend: send,
@@ -2004,7 +2115,7 @@ function ChatPanel({
2004
2115
  }
2005
2116
 
2006
2117
  // src/components/chat/FrankieWidget.tsx
2007
- var import_jsx_runtime16 = require("react/jsx-runtime");
2118
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2008
2119
  function FrankieWidget({
2009
2120
  position = "bottom-right",
2010
2121
  offset = 24,
@@ -2015,6 +2126,7 @@ function FrankieWidget({
2015
2126
  renderLauncher,
2016
2127
  launcher = true,
2017
2128
  avoidBottomBars = true,
2129
+ closeOnOutsideClick = true,
2018
2130
  ...panelProps
2019
2131
  }) {
2020
2132
  const { config, injectStyles, themeReady } = useFrankie();
@@ -2035,6 +2147,17 @@ function FrankieWidget({
2035
2147
  window.addEventListener("keydown", onKeyDown);
2036
2148
  return () => window.removeEventListener("keydown", onKeyDown);
2037
2149
  }, [open]);
2150
+ (0, import_react11.useEffect)(() => {
2151
+ if (!open || !closeOnOutsideClick) return;
2152
+ const onPointerDown = (event) => {
2153
+ const target = event.target;
2154
+ if (!(target instanceof Node) || !target.isConnected || rootRef.current?.contains(target)) return;
2155
+ if (target instanceof Element && target.closest("[data-frankie-open], [data-frankie-keep-open]")) return;
2156
+ setOpen(false);
2157
+ };
2158
+ document.addEventListener("pointerdown", onPointerDown, true);
2159
+ return () => document.removeEventListener("pointerdown", onPointerDown, true);
2160
+ }, [open, closeOnOutsideClick]);
2038
2161
  (0, import_react11.useEffect)(() => {
2039
2162
  const onClick = (event) => {
2040
2163
  const target = event.target instanceof Element ? event.target.closest("[data-frankie-open]") : null;
@@ -2078,7 +2201,7 @@ function FrankieWidget({
2078
2201
  const label = config?.branding.launcherLabel ?? "Need a hand?";
2079
2202
  const mode = useResolvedMode(theme?.mode);
2080
2203
  const side = position === "bottom-right" ? { right: offset } : { left: offset };
2081
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2204
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2082
2205
  "div",
2083
2206
  {
2084
2207
  ref: rootRef,
@@ -2086,9 +2209,9 @@ function FrankieWidget({
2086
2209
  style: { ...themeToCssVars(theme), position: "fixed", bottom: lift ? lift + Math.min(offset, 12) : offset, ...side, zIndex, pointerEvents: "none", ["--frankie-lift"]: `${lift}px`, ...stylesReady && themeReady ? null : { opacity: 0 } },
2087
2210
  "data-frankie-mode": mode,
2088
2211
  "data-frankie-styles": stylesReady ? "ready" : "pending",
2089
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("flex flex-col gap-3", position === "bottom-left" ? "items-start" : "items-end"), children: [
2090
- open ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatPanel, { ...panelProps, className: cn("frankie-widget-panel", panelProps.className), onClose: () => setOpen(false), autoFocus: true }) }) : null,
2091
- launcher || renderLauncher ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { pointerEvents: "auto" }, children: renderLauncher ? renderLauncher({ open, toggle: () => setOpen(!open), label }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2212
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: cn("flex flex-col gap-3", position === "bottom-left" ? "items-start" : "items-end"), children: [
2213
+ open ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { pointerEvents: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatPanel, { ...panelProps, className: cn("frankie-widget-panel", panelProps.className), onClose: () => setOpen(false), autoFocus: true }) }) : null,
2214
+ launcher || renderLauncher ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { pointerEvents: "auto" }, children: renderLauncher ? renderLauncher({ open, toggle: () => setOpen(!open), label }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2092
2215
  Button,
2093
2216
  {
2094
2217
  size: "icon",
@@ -2097,7 +2220,7 @@ function FrankieWidget({
2097
2220
  "aria-expanded": open,
2098
2221
  "aria-label": open ? "Close the assistant" : label,
2099
2222
  title: label,
2100
- children: open ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.X, { className: "size-5" }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react8.MessageCircle, { className: "size-5" })
2223
+ children: open ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react9.X, { className: "size-5" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react9.MessageCircle, { className: "size-5" })
2101
2224
  }
2102
2225
  ) }) : null
2103
2226
  ] })
@@ -2107,14 +2230,14 @@ function FrankieWidget({
2107
2230
 
2108
2231
  // src/components/chat/FrankieInline.tsx
2109
2232
  var import_react12 = require("react");
2110
- var import_jsx_runtime17 = require("react/jsx-runtime");
2233
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2111
2234
  function FrankieInline({ className, style, ...panelProps }) {
2112
2235
  const { injectStyles, themeReady } = useFrankie();
2113
2236
  const theme = useFrankieTheme();
2114
2237
  const mode = useResolvedMode(theme?.mode);
2115
2238
  const rootRef = (0, import_react12.useRef)(null);
2116
2239
  const stylesReady = useStylesReady(rootRef, void 0, injectStyles);
2117
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2240
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2118
2241
  "div",
2119
2242
  {
2120
2243
  ref: rootRef,
@@ -2122,14 +2245,14 @@ function FrankieInline({ className, style, ...panelProps }) {
2122
2245
  style: { ...themeToCssVars(theme), display: "flex", height: "100%", width: "100%", ...style, ...stylesReady && themeReady ? null : { opacity: 0 } },
2123
2246
  "data-frankie-mode": mode,
2124
2247
  "data-frankie-styles": stylesReady ? "ready" : "pending",
2125
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatPanel, { ...panelProps, fill: true })
2248
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ChatPanel, { ...panelProps, fill: true })
2126
2249
  }
2127
2250
  );
2128
2251
  }
2129
2252
 
2130
2253
  // src/components/chat/FrankieChatPage.tsx
2131
2254
  var import_react14 = require("react");
2132
- var import_lucide_react9 = require("lucide-react");
2255
+ var import_lucide_react10 = require("lucide-react");
2133
2256
 
2134
2257
  // src/lib/viewport-fill.ts
2135
2258
  var import_react13 = require("react");
@@ -2171,7 +2294,7 @@ function useViewportFill(ref, enabled) {
2171
2294
  }
2172
2295
 
2173
2296
  // src/components/chat/FrankieChatPage.tsx
2174
- var import_jsx_runtime18 = require("react/jsx-runtime");
2297
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2175
2298
  function groupByDate(items) {
2176
2299
  const now = /* @__PURE__ */ new Date();
2177
2300
  const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
@@ -2264,70 +2387,70 @@ function PageChrome({ showHistory, navigation, currentId, onSelect, onNew, histo
2264
2387
  close();
2265
2388
  }
2266
2389
  };
2267
- const history = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2268
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-history-heading", children: [
2269
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: "Conversations" }),
2270
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "frankie-mobile-only", "aria-label": "Close conversations", onClick: close, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.X, { size: 18 }) })
2390
+ const history = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2391
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "frankie-history-heading", children: [
2392
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: "Conversations" }),
2393
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "frankie-mobile-only", "aria-label": "Close conversations", onClick: close, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.X, { size: 18 }) })
2271
2394
  ] }),
2272
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", className: "frankie-new-chat", disabled: busy, onClick: () => {
2395
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: "frankie-new-chat", disabled: busy, onClick: () => {
2273
2396
  onNew();
2274
2397
  close();
2275
2398
  }, children: [
2276
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.Plus, { size: 17 }),
2399
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.Plus, { size: 17 }),
2277
2400
  "New chat"
2278
2401
  ] }),
2279
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("label", { className: "frankie-history-search", children: [
2280
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Search conversations" }),
2281
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { type: "search", placeholder: "Search chats\u2026", value: query, onChange: (event) => setQuery(event.target.value) })
2402
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { className: "frankie-history-search", children: [
2403
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Search conversations" }),
2404
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { type: "search", placeholder: "Search chats\u2026", value: query, onChange: (event) => setQuery(event.target.value) })
2282
2405
  ] }),
2283
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("nav", { className: "frankie-history-list", "aria-label": "Conversations", children: groupByDate(conversations.filter((item) => item.title.toLowerCase().includes(query.toLowerCase()))).map((group) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-history-group", children: [
2284
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "frankie-history-group-label", children: group.label }),
2285
- group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", "aria-current": item.id === currentId ? "page" : void 0, disabled: busy, onClick: () => select(item.id), children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: item.title }),
2287
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("small", { children: new Date(item.updatedAt).toLocaleDateString() })
2406
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("nav", { className: "frankie-history-list", "aria-label": "Conversations", children: groupByDate(conversations.filter((item) => item.title.toLowerCase().includes(query.toLowerCase()))).map((group) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "frankie-history-group", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "frankie-history-group-label", children: group.label }),
2408
+ group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", "aria-current": item.id === currentId ? "page" : void 0, disabled: busy, onClick: () => select(item.id), children: [
2409
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: item.title }),
2410
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { children: new Date(item.updatedAt).toLocaleDateString() })
2288
2411
  ] }, item.id))
2289
2412
  ] }, group.label)) }),
2290
- historyLoading && !conversations.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", children: "Loading history\u2026" }) : historyError ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { role: "status", children: [
2413
+ historyLoading && !conversations.length ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "status", children: "Loading history\u2026" }) : historyError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { role: "status", children: [
2291
2414
  historyError,
2292
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: () => void refresh(), children: "Try again" })
2293
- ] }) : !conversations.length && !historyLoading ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: config?.allowAnonymous ? "Sign in to sync conversations across devices." : "Your conversations will appear here." }) : null,
2294
- navigation ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "frankie-host-navigation", children: navigation }) : null
2415
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: () => void refresh(), children: "Try again" })
2416
+ ] }) : !conversations.length && !historyLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: config?.allowAnonymous ? "Sign in to sync conversations across devices." : "Your conversations will appear here." }) : null,
2417
+ navigation ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "frankie-host-navigation", children: navigation }) : null
2295
2418
  ] });
2296
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-page-shell" + (mode === "dark" ? " dark" : ""), style: { ...themeToCssVars(theme), ...themeReady ? null : { opacity: 0 } }, children: [
2297
- showHistory ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("aside", { className: "frankie-history-desktop" + (collapsed ? " frankie-history-collapsed" : ""), children: [
2298
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "frankie-history-toggle", "aria-label": collapsed ? "Expand conversations" : "Collapse conversations", "aria-expanded": !collapsed, onClick: () => setCollapsed((value) => !value), children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.ChevronsRight, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.ChevronsLeft, { size: 16 }) }),
2419
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "frankie-page-shell" + (mode === "dark" ? " dark" : ""), style: { ...themeToCssVars(theme), ...themeReady ? null : { opacity: 0 } }, children: [
2420
+ showHistory ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("aside", { className: "frankie-history-desktop" + (collapsed ? " frankie-history-collapsed" : ""), children: [
2421
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "frankie-history-toggle", "aria-label": collapsed ? "Expand conversations" : "Collapse conversations", "aria-expanded": !collapsed, onClick: () => setCollapsed((value) => !value), children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.ChevronsRight, { size: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.ChevronsLeft, { size: 16 }) }),
2299
2422
  collapsed ? null : history
2300
2423
  ] }) : null,
2301
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-page-main", children: [
2302
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("header", { className: "frankie-page-header", children: [
2303
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
2304
- showHistory ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "frankie-mobile-only", ref: menu, "aria-label": "Open conversations", "aria-haspopup": "dialog", "aria-expanded": drawerOpen, onClick: () => setDrawerOpen(true), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.Menu, { size: 20 }) }) : null,
2305
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { className: "frankie-thread-title", children: conversations.find((item) => item.id === currentId)?.title ?? messages.find((message) => message.role === "user")?.text ?? "New chat" })
2424
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "frankie-page-main", children: [
2425
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("header", { className: "frankie-page-header", children: [
2426
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
2427
+ showHistory ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "frankie-mobile-only", ref: menu, "aria-label": "Open conversations", "aria-haspopup": "dialog", "aria-expanded": drawerOpen, onClick: () => setDrawerOpen(true), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.Menu, { size: 20 }) }) : null,
2428
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { className: "frankie-thread-title", children: conversations.find((item) => item.id === currentId)?.title ?? messages.find((message) => message.role === "user")?.text ?? "New chat" })
2306
2429
  ] }),
2307
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
2308
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", disabled: busy, onClick: onNew, "aria-label": "Start a new conversation", children: [
2309
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.Plus, { size: 16 }),
2310
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "New chat" })
2430
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
2431
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", disabled: busy, onClick: onNew, "aria-label": "Start a new conversation", children: [
2432
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.Plus, { size: 16 }),
2433
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "New chat" })
2311
2434
  ] }),
2312
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("details", { className: "frankie-chat-settings", children: [
2313
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("summary", { "aria-label": "Chat settings", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.Settings, { size: 19 }) }),
2314
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
2315
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: "Chat settings" }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { children: "History syncs automatically for signed-in users." }),
2317
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("button", { type: "button", onClick: () => void refresh(), disabled: historyLoading || !showHistory, children: [
2318
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.History, { size: 16 }),
2435
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("details", { className: "frankie-chat-settings", children: [
2436
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { "aria-label": "Chat settings", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.Settings, { size: 19 }) }),
2437
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
2438
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: "Chat settings" }),
2439
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { children: "History syncs automatically for signed-in users." }),
2440
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", onClick: () => void refresh(), disabled: historyLoading || !showHistory, children: [
2441
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react10.History, { size: 16 }),
2319
2442
  "Refresh history"
2320
2443
  ] }),
2321
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("small", { children: "Skills are checked at the start of each message." })
2444
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { children: "Skills are checked at the start of each message." })
2322
2445
  ] })
2323
2446
  ] })
2324
2447
  ] })
2325
2448
  ] }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "frankie-page-canvas", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FrankieInline, { ...panel, header: panel.header ?? false, placeholder: panel.placeholder ?? `Ask anything about your ${config?.branding.name ?? "Frankie"} workspace\u2026`, emptyState: panel.emptyState }) })
2449
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "frankie-page-canvas", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrankieInline, { ...panel, header: panel.header ?? false, placeholder: panel.placeholder ?? `Ask anything about your ${config?.branding.name ?? "Frankie"} workspace\u2026`, emptyState: panel.emptyState }) })
2327
2450
  ] }),
2328
- showHistory ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dialog", { ref: dialog, className: "frankie-history-dialog frankie-root", "aria-label": "Chat conversations", style: themeToCssVars(theme), onCancel: close, onClick: (event) => {
2451
+ showHistory ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("dialog", { ref: dialog, className: "frankie-history-dialog frankie-root", "aria-label": "Chat conversations", style: themeToCssVars(theme), onCancel: close, onClick: (event) => {
2329
2452
  if (event.target === event.currentTarget) close();
2330
- }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("aside", { children: history }) }) : null
2453
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("aside", { children: history }) }) : null
2331
2454
  ] });
2332
2455
  }
2333
2456
  function FrankieChatPage({ className, style, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus, showHistory = true, navigation, fillViewport = true, ...provider }) {
@@ -2337,18 +2460,18 @@ function FrankieChatPage({ className, style, header, footer, emptyState, renderM
2337
2460
  const pageRef = (0, import_react14.useRef)(null);
2338
2461
  const stylesReady = useStylesReady(pageRef, void 0, provider.injectStyles);
2339
2462
  const fill = useViewportFill(pageRef, fillViewport);
2340
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: pageRef, className: ["frankie-root", "frankie-chat-page", className].filter(Boolean).join(" "), style: { height: "100%", minHeight: fill > 360 ? `${fill}px` : "min(36rem, 100dvh)", width: "100%", ...style, ...stylesReady ? null : { opacity: 0 } }, "data-frankie-styles": stylesReady ? "ready" : "pending", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FrankieProvider, { ...provider, conversationId: id, storageNamespace: (provider.storageNamespace ?? "frankie." + provider.publishableKey) + "." + id, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PageChrome, { showHistory, navigation, currentId: id, onSelect: setId, onNew, history, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus }) }) });
2463
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: pageRef, className: ["frankie-root", "frankie-chat-page", className].filter(Boolean).join(" "), style: { height: "100%", minHeight: fill > 360 ? `${fill}px` : "min(36rem, 100dvh)", width: "100%", ...style, ...stylesReady ? null : { opacity: 0 } }, "data-frankie-styles": stylesReady ? "ready" : "pending", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrankieProvider, { ...provider, conversationId: id, storageNamespace: (provider.storageNamespace ?? "frankie." + provider.publishableKey) + "." + id, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PageChrome, { showHistory, navigation, currentId: id, onSelect: setId, onNew, history, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus }) }) });
2341
2464
  }
2342
2465
 
2343
2466
  // src/components/chat/SuggestedPrompts.tsx
2344
- var import_jsx_runtime19 = require("react/jsx-runtime");
2467
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2345
2468
  function SuggestedPrompts({
2346
2469
  prompts,
2347
2470
  onPick,
2348
2471
  disabled
2349
2472
  }) {
2350
2473
  if (prompts.length === 0) return null;
2351
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-2", children: prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2474
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-2", children: prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2352
2475
  Button,
2353
2476
  {
2354
2477
  type: "button",
@@ -2363,12 +2486,13 @@ function SuggestedPrompts({
2363
2486
  }
2364
2487
 
2365
2488
  // src/components/ui/separator.tsx
2366
- var import_jsx_runtime20 = require("react/jsx-runtime");
2489
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2367
2490
  function Separator({ className }) {
2368
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "separator", className: cn("h-px w-full bg-border", className) });
2491
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "separator", className: cn("h-px w-full bg-border", className) });
2369
2492
  }
2370
2493
  // Annotate the CommonJS export names for ESM import in node:
2371
2494
  0 && (module.exports = {
2495
+ ActionConfirm,
2372
2496
  Avatar,
2373
2497
  Badge,
2374
2498
  Button,