@frankieai/react 0.2.17 → 0.2.19

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
@@ -61,7 +61,8 @@ __export(index_exports, {
61
61
  themeToCssVars: () => themeToCssVars,
62
62
  useFrankie: () => useFrankie,
63
63
  useFrankieChat: () => useFrankieChat,
64
- useFrankieTheme: () => useFrankieTheme
64
+ useFrankieTheme: () => useFrankieTheme,
65
+ useResolvedMode: () => useResolvedMode
65
66
  });
66
67
  module.exports = __toCommonJS(index_exports);
67
68
 
@@ -209,6 +210,22 @@ var FrankieClient = class {
209
210
  const body = await this.unwrap(response);
210
211
  return Array.isArray(body.conversations) ? body.conversations : [];
211
212
  }
213
+ /** Whether a conversation can be reloaded from the server (a signed-in user and a conversation id). */
214
+ get canResume() {
215
+ return Boolean(this.options.conversationId && this.options.getUserToken);
216
+ }
217
+ /**
218
+ * Ask the server to stop the running turn. Closing the stream no longer
219
+ * stops it (a closed tab shouldn't lose the reply), so Stop says so
220
+ * explicitly. Best effort: the stream is closed right after either way.
221
+ */
222
+ async stopTurn() {
223
+ if (!this.session) return;
224
+ await this.doFetch(`${this.baseUrl}/v1/chat/stop`, {
225
+ method: "POST",
226
+ headers: { "x-frankie-key": this.options.publishableKey, authorization: `Bearer ${this.session.sessionToken}` }
227
+ }).catch(() => void 0);
228
+ }
212
229
  async resumeConversation(id = this.options.conversationId) {
213
230
  if (!id || !this.options.getUserToken) return void 0;
214
231
  const userToken = await this.requireUserToken();
@@ -221,7 +238,7 @@ var FrankieClient = class {
221
238
  this.session = body.session;
222
239
  this.sessionUserKey = sessionIdentity(userToken);
223
240
  this.writeStored();
224
- return { messages: Array.isArray(body.messages) ? body.messages : [], title: body.title ?? "New chat" };
241
+ return { messages: Array.isArray(body.messages) ? body.messages : [], title: body.title ?? "New chat", busy: body.busy === true };
225
242
  }
226
243
  async syncConversation(messages, title) {
227
244
  if (!this.session || !this.options.conversationId) return;
@@ -662,6 +679,30 @@ function useFrankieChatState() {
662
679
  };
663
680
  }, []);
664
681
  const storageKey = `${client.namespace}.messages`;
682
+ const followingRef = (0, import_react.useRef)(false);
683
+ const followRunningTurn = (0, import_react.useCallback)(async () => {
684
+ if (followingRef.current || !client.canResume) return;
685
+ followingRef.current = true;
686
+ setBusy(true);
687
+ try {
688
+ const deadline = Date.now() + 3 * 6e4;
689
+ while (mounted.current && Date.now() < deadline) {
690
+ await new Promise((resolve) => setTimeout(resolve, 2500));
691
+ const remote = await client.resumeConversation().catch(() => void 0);
692
+ if (!remote || remote.busy) continue;
693
+ if (remote.messages.length) {
694
+ const finished = remote.messages;
695
+ messagesRef.current = finished;
696
+ if (mounted.current) setMessages(finished);
697
+ }
698
+ if (mounted.current) setError(void 0);
699
+ return;
700
+ }
701
+ } finally {
702
+ followingRef.current = false;
703
+ if (mounted.current) setBusy(false);
704
+ }
705
+ }, [client]);
665
706
  (0, import_react.useEffect)(() => {
666
707
  let active = true;
667
708
  const restore = async () => {
@@ -679,10 +720,11 @@ function useFrankieChatState() {
679
720
  try {
680
721
  const remote = await client.resumeConversation();
681
722
  if (active && remote?.messages.length) {
682
- const restoredMessages = remote.messages;
723
+ const restoredMessages = remote.busy ? stillWorking(remote.messages) : remote.messages;
683
724
  messagesRef.current = restoredMessages;
684
725
  setMessages(restoredMessages);
685
726
  }
727
+ if (active && remote?.busy) void followRunningTurn();
686
728
  } catch (caught) {
687
729
  if (active) {
688
730
  const message = caught instanceof FrankieApiError ? caught.message : caught instanceof Error && caught.message.startsWith("Frankie") ? caught.message : "Could not restore this conversation. Check your sign-in and connection, then try opening it again.";
@@ -696,7 +738,7 @@ function useFrankieChatState() {
696
738
  return () => {
697
739
  active = false;
698
740
  };
699
- }, [client, storageKey]);
741
+ }, [client, storageKey, followRunningTurn]);
700
742
  (0, import_react.useEffect)(() => {
701
743
  if (!client.persist || !restored || busy) return;
702
744
  try {
@@ -772,6 +814,7 @@ function useFrankieChatState() {
772
814
  pendingThinking = "";
773
815
  patchAssistant(assistantId, (message) => ({ ...message, text: message.text + addText, thinking: message.thinking + addThinking }));
774
816
  };
817
+ let lostStream = false;
775
818
  try {
776
819
  let receivedText = false;
777
820
  let receivedToolActivity = false;
@@ -825,6 +868,8 @@ function useFrankieChatState() {
825
868
  status: "done",
826
869
  text: message.text || "Stopped."
827
870
  }));
871
+ } else if (!(caught instanceof FrankieApiError) && client.canResume) {
872
+ lostStream = true;
828
873
  } else {
829
874
  const message = caught instanceof FrankieApiError ? caught.message : caught instanceof Error && caught.message.startsWith("Frankie") ? caught.message : "Could not reach the assistant. Check your connection and try again.";
830
875
  if (mounted.current) setError(message);
@@ -832,21 +877,28 @@ function useFrankieChatState() {
832
877
  }
833
878
  } finally {
834
879
  flushDeltas();
835
- patchAssistant(
836
- assistantId,
837
- (message) => message.status === "streaming" ? { ...message, status: "done" } : message
838
- );
880
+ if (!lostStream) {
881
+ patchAssistant(
882
+ assistantId,
883
+ (message) => message.status === "streaming" ? { ...message, status: "done" } : message
884
+ );
885
+ }
839
886
  const transcript = messagesRef.current;
840
887
  if (transcript.length) {
841
888
  await client.syncConversation(transcript, conversationTitle(transcript)).catch(() => void 0);
842
889
  }
843
890
  if (mounted.current) setBusy(false);
844
891
  abortRef.current = null;
892
+ if (lostStream) void followRunningTurn();
845
893
  }
846
894
  },
847
- [busy, client, context, patchAssistant, restored]
895
+ [busy, client, context, patchAssistant, restored, followRunningTurn]
848
896
  );
849
- const stop = (0, import_react.useCallback)(() => abortRef.current?.abort(), []);
897
+ const stop = (0, import_react.useCallback)(() => {
898
+ if (!abortRef.current) return;
899
+ void client.stopTurn();
900
+ abortRef.current.abort();
901
+ }, [client]);
850
902
  const reset = (0, import_react.useCallback)(() => {
851
903
  abortRef.current?.abort();
852
904
  client.resetSession();
@@ -870,9 +922,15 @@ function conversationTitle(messages) {
870
922
  const title = first.text.trim().replace(/\s+/g, " ");
871
923
  return title.length > 42 ? `${title.slice(0, 42)}\u2026` : title;
872
924
  }
925
+ function stillWorking(messages) {
926
+ const last = messages[messages.length - 1];
927
+ if (last?.role === "assistant") return [...messages.slice(0, -1), { ...last, status: "streaming", error: void 0 }];
928
+ return [...messages, { id: "pending_" + Date.now(), role: "assistant", text: "", thinking: "", tools: [], status: "streaming", createdAt: Date.now() }];
929
+ }
873
930
 
874
931
  // src/hooks/FrankieProvider.tsx
875
932
  var import_jsx_runtime = require("react/jsx-runtime");
933
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react2.useEffect : import_react2.useLayoutEffect;
876
934
  var FrankieContext = (0, import_react2.createContext)(null);
877
935
  function FrankieProvider({
878
936
  children,
@@ -912,7 +970,8 @@ function FrankieProvider({
912
970
  }, [configKey, providedConfig]);
913
971
  const inheriting = (theme?.source ?? config?.theme?.source) === "inherit";
914
972
  const [hostTheme, setHostTheme] = (0, import_react2.useState)(null);
915
- (0, import_react2.useEffect)(() => {
973
+ const [hostSampled, setHostSampled] = (0, import_react2.useState)(false);
974
+ useIsomorphicLayoutEffect(() => {
916
975
  if (!inheriting) {
917
976
  setHostTheme(null);
918
977
  return;
@@ -922,6 +981,7 @@ function FrankieProvider({
922
981
  return JSON.stringify(previous) === JSON.stringify(next) ? previous : next;
923
982
  });
924
983
  sample();
984
+ setHostSampled(true);
925
985
  return watchHostTheme(sample);
926
986
  }, [inheriting]);
927
987
  const value = (0, import_react2.useMemo)(
@@ -933,9 +993,10 @@ function FrankieProvider({
933
993
  ...context ? { context } : {},
934
994
  ...theme ? { theme } : {},
935
995
  injectStyles,
936
- hostTheme
996
+ hostTheme,
997
+ themeReady: Boolean(config || configError) && (!inheriting || hostSampled)
937
998
  }),
938
- [client, config, configError, loading, context, theme, injectStyles, hostTheme]
999
+ [client, config, configError, loading, context, theme, injectStyles, hostTheme, inheriting, hostSampled]
939
1000
  );
940
1001
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FrankieContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationState, { children }, client.namespace + ":" + (client.conversationId ?? "")) });
941
1002
  }
@@ -960,14 +1021,14 @@ function useFrankieTheme() {
960
1021
 
961
1022
  // src/components/chat/FrankieWidget.tsx
962
1023
  var import_lucide_react8 = require("lucide-react");
963
- var import_react10 = require("react");
1024
+ var import_react11 = require("react");
964
1025
 
965
1026
  // src/lib/styles-ready.ts
966
1027
  var import_react3 = require("react");
967
1028
 
968
1029
  // src/generated/css-content.ts
969
1030
  var FRANKIE_CSS_CONTENT = `/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
970
- @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)}.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}@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 .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-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-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 .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) 26%, transparent) 37%, color-mix(in srgb, var(--frankie-muted-foreground) 11%, transparent) 63%)}}.frankie-root .frankie-skeleton-line{background-size:400% 100%;animation:1.4s infinite frankie-shimmer}@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}}`;
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}}`;
971
1032
 
972
1033
  // src/lib/ensure-frankie-styles.ts
973
1034
  var STYLE_ELEMENT_ID = "frankie-fallback-styles";
@@ -983,11 +1044,11 @@ function ensureFrankieStyles() {
983
1044
  }
984
1045
 
985
1046
  // src/lib/styles-ready.ts
986
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react3.useEffect : import_react3.useLayoutEffect;
1047
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? import_react3.useEffect : import_react3.useLayoutEffect;
987
1048
  var SENTINEL = "--frankie-styles-ready";
988
1049
  function useStylesReady(ref, timeoutMs = 600, injectFallback = true) {
989
1050
  const [ready, setReady] = (0, import_react3.useState)(false);
990
- useIsomorphicLayoutEffect(() => {
1051
+ useIsomorphicLayoutEffect2(() => {
991
1052
  if (ready) return;
992
1053
  const node = ref.current;
993
1054
  if (!node || typeof window === "undefined" || typeof window.getComputedStyle !== "function") {
@@ -1023,7 +1084,42 @@ function useStylesReady(ref, timeoutMs = 600, injectFallback = true) {
1023
1084
  return ready;
1024
1085
  }
1025
1086
 
1087
+ // src/lib/bottom-bars.ts
1088
+ function bottomObstruction(root, position, offset) {
1089
+ if (typeof document === "undefined" || typeof window === "undefined" || typeof document.elementsFromPoint !== "function") return 0;
1090
+ const width = window.innerWidth;
1091
+ const height = window.innerHeight;
1092
+ if (!width || !height) return 0;
1093
+ const xs = position === "bottom-right" ? [width - offset - 24, width - 8] : [offset + 24, 8];
1094
+ const ys = [height - offset - 24, height - 4];
1095
+ let lift = 0;
1096
+ const seen = /* @__PURE__ */ new Set();
1097
+ for (const x of xs) for (const y of ys) {
1098
+ for (const hit of document.elementsFromPoint(x, y)) {
1099
+ if (root?.contains(hit)) continue;
1100
+ const bar = anchoredAncestor(hit);
1101
+ if (!bar || seen.has(bar)) continue;
1102
+ seen.add(bar);
1103
+ const rect = bar.getBoundingClientRect();
1104
+ 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);
1107
+ }
1108
+ }
1109
+ return Math.round(lift);
1110
+ }
1111
+ function anchoredAncestor(element) {
1112
+ let node = element;
1113
+ for (let depth = 0; node && depth < 8 && node !== document.body && node !== document.documentElement; depth += 1) {
1114
+ const position = getComputedStyle(node).position;
1115
+ if (position === "fixed" || position === "sticky") return node;
1116
+ node = node.parentElement;
1117
+ }
1118
+ return null;
1119
+ }
1120
+
1026
1121
  // src/lib/theme.ts
1122
+ var import_react4 = require("react");
1027
1123
  function themeToCssVars(theme) {
1028
1124
  if (!theme) return {};
1029
1125
  const vars = {};
@@ -1042,6 +1138,18 @@ function resolveMode(mode) {
1042
1138
  if (typeof window === "undefined" || !window.matchMedia) return "light";
1043
1139
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1044
1140
  }
1141
+ var DARK_QUERY = "(prefers-color-scheme: dark)";
1142
+ function subscribeToScheme(onChange) {
1143
+ const media = typeof window !== "undefined" && window.matchMedia ? window.matchMedia(DARK_QUERY) : void 0;
1144
+ media?.addEventListener?.("change", onChange);
1145
+ return () => media?.removeEventListener?.("change", onChange);
1146
+ }
1147
+ var prefersDark = () => typeof window !== "undefined" && Boolean(window.matchMedia?.(DARK_QUERY).matches);
1148
+ function useResolvedMode(mode) {
1149
+ const dark = (0, import_react4.useSyncExternalStore)(subscribeToScheme, prefersDark, () => false);
1150
+ if (mode === "light" || mode === "dark") return mode;
1151
+ return dark ? "dark" : "light";
1152
+ }
1045
1153
 
1046
1154
  // src/lib/utils.ts
1047
1155
  var import_clsx = require("clsx");
@@ -1082,7 +1190,7 @@ function Button({ className, variant, size, asChild = false, ...props }) {
1082
1190
 
1083
1191
  // src/components/chat/ChatPanel.tsx
1084
1192
  var import_lucide_react7 = require("lucide-react");
1085
- var import_react9 = require("react");
1193
+ var import_react10 = require("react");
1086
1194
 
1087
1195
  // src/components/ui/avatar.tsx
1088
1196
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -1132,9 +1240,9 @@ function CardFooter({ className, ...props }) {
1132
1240
  }
1133
1241
 
1134
1242
  // src/components/ui/scroll-area.tsx
1135
- var import_react4 = require("react");
1243
+ var import_react5 = require("react");
1136
1244
  var import_jsx_runtime5 = require("react/jsx-runtime");
1137
- var ScrollArea = (0, import_react4.forwardRef)(
1245
+ var ScrollArea = (0, import_react5.forwardRef)(
1138
1246
  function ScrollArea2({ className, ...props }, ref) {
1139
1247
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref, className: cn("frankie-scroll overflow-y-auto overscroll-contain", className), ...props });
1140
1248
  }
@@ -1229,7 +1337,7 @@ function ChatEmptyState() {
1229
1337
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "frankie-page-suggest-label", children: "Try asking me to" }),
1230
1338
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "frankie-page-prompts", children: starters.map((card, index) => {
1231
1339
  const Icon = card.icon && NAMED_ICONS[card.icon] || PROMPT_ICONS[index % PROMPT_ICONS.length];
1232
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy || restoring, onClick: () => void send(card.message), children: [
1340
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy || restoring, onClick: () => void send(card.message), title: card.description || void 0, children: [
1233
1341
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "frankie-prompt-icon", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { size: 18 }) }),
1234
1342
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "frankie-prompt-text", children: [
1235
1343
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: card.title }),
@@ -1244,12 +1352,12 @@ function ChatEmptyState() {
1244
1352
 
1245
1353
  // src/components/chat/Composer.tsx
1246
1354
  var import_lucide_react3 = require("lucide-react");
1247
- var import_react6 = require("react");
1355
+ var import_react7 = require("react");
1248
1356
 
1249
1357
  // src/components/ui/textarea.tsx
1250
- var import_react5 = require("react");
1358
+ var import_react6 = require("react");
1251
1359
  var import_jsx_runtime8 = require("react/jsx-runtime");
1252
- var Textarea = (0, import_react5.forwardRef)(
1360
+ var Textarea = (0, import_react6.forwardRef)(
1253
1361
  function Textarea2({ className, ...props }, ref) {
1254
1362
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1255
1363
  "textarea",
@@ -1269,12 +1377,12 @@ var Textarea = (0, import_react5.forwardRef)(
1269
1377
  var import_jsx_runtime9 = require("react/jsx-runtime");
1270
1378
  var MAX_ROWS_PX = 140;
1271
1379
  function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, attachments, modelPicker, focusHandleRef }) {
1272
- const [value, setValue] = (0, import_react6.useState)("");
1273
- const [files, setFiles] = (0, import_react6.useState)([]);
1274
- const [fileError, setFileError] = (0, import_react6.useState)(void 0);
1275
- const textareaRef = (0, import_react6.useRef)(null);
1276
- const fileInputRef = (0, import_react6.useRef)(null);
1277
- (0, import_react6.useEffect)(() => {
1380
+ const [value, setValue] = (0, import_react7.useState)("");
1381
+ const [files, setFiles] = (0, import_react7.useState)([]);
1382
+ const [fileError, setFileError] = (0, import_react7.useState)(void 0);
1383
+ const textareaRef = (0, import_react7.useRef)(null);
1384
+ const fileInputRef = (0, import_react7.useRef)(null);
1385
+ (0, import_react7.useEffect)(() => {
1278
1386
  if (!focusHandleRef) return;
1279
1387
  focusHandleRef.current = () => textareaRef.current?.focus();
1280
1388
  return () => {
@@ -1283,13 +1391,13 @@ function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, atta
1283
1391
  }, [focusHandleRef]);
1284
1392
  const canAttach = Boolean(attachments?.enabled);
1285
1393
  const models = modelPicker?.models ?? [];
1286
- (0, import_react6.useEffect)(() => {
1394
+ (0, import_react7.useEffect)(() => {
1287
1395
  const node = textareaRef.current;
1288
1396
  if (!node) return;
1289
1397
  node.style.height = "auto";
1290
1398
  node.style.height = `${Math.min(node.scrollHeight, MAX_ROWS_PX)}px`;
1291
1399
  }, [value]);
1292
- const addFiles = (0, import_react6.useCallback)(
1400
+ const addFiles = (0, import_react7.useCallback)(
1293
1401
  async (list) => {
1294
1402
  if (!list || !attachments) return;
1295
1403
  setFileError(void 0);
@@ -1322,7 +1430,7 @@ function Composer({ onSend, onStop, busy, placeholder, disabled, autoFocus, atta
1322
1430
  [attachments, files.length]
1323
1431
  );
1324
1432
  const removeFile = (id) => setFiles((current) => current.filter((file) => file.id !== id));
1325
- const submit = (0, import_react6.useCallback)(() => {
1433
+ const submit = (0, import_react7.useCallback)(() => {
1326
1434
  const text = value.trim();
1327
1435
  if (!text && files.length === 0 || busy || disabled) return;
1328
1436
  setValue("");
@@ -1458,7 +1566,7 @@ function readAsBase64(file) {
1458
1566
 
1459
1567
  // src/components/chat/MessageBubble.tsx
1460
1568
  var import_lucide_react6 = require("lucide-react");
1461
- var import_react8 = require("react");
1569
+ var import_react9 = require("react");
1462
1570
 
1463
1571
  // src/lib/choices.ts
1464
1572
  var CLOSED = /```frankie:choices[ \t]*\r?\n([\s\S]*?)```/;
@@ -1522,10 +1630,10 @@ function Choices({
1522
1630
  }
1523
1631
 
1524
1632
  // src/components/chat/Markdown.tsx
1525
- var import_react7 = require("react");
1633
+ var import_react8 = require("react");
1526
1634
  var import_jsx_runtime11 = require("react/jsx-runtime");
1527
- var Markdown = (0, import_react7.memo)(function Markdown2({ text, className }) {
1528
- const blocks = (0, import_react7.useMemo)(() => renderBlocks(text), [text]);
1635
+ var Markdown = (0, import_react8.memo)(function Markdown2({ text, className }) {
1636
+ const blocks = (0, import_react8.useMemo)(() => renderBlocks(text), [text]);
1529
1637
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("frankie-prose", className), children: blocks });
1530
1638
  });
1531
1639
  function renderBlocks(text) {
@@ -1610,7 +1718,7 @@ function renderInline(text) {
1610
1718
  const token = match[0];
1611
1719
  const start = match.index;
1612
1720
  if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
1613
- nodes.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react7.Fragment, { children: renderToken(token) }, start));
1721
+ nodes.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react8.Fragment, { children: renderToken(token) }, start));
1614
1722
  lastIndex = start + token.length;
1615
1723
  }
1616
1724
  if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
@@ -1704,7 +1812,7 @@ function badgeVariant(status) {
1704
1812
 
1705
1813
  // src/components/chat/MessageBubble.tsx
1706
1814
  var import_jsx_runtime14 = require("react/jsx-runtime");
1707
- var MessageBubble = (0, import_react8.memo)(function MessageBubble2({
1815
+ var MessageBubble = (0, import_react9.memo)(function MessageBubble2({
1708
1816
  message,
1709
1817
  assistantName,
1710
1818
  avatarUrl,
@@ -1736,8 +1844,7 @@ var MessageBubble = (0, import_react8.memo)(function MessageBubble2({
1736
1844
  }
1737
1845
  const { body, options } = extractChoices(message.text);
1738
1846
  const showChoices = Boolean(active && onChoose && options && message.status === "done");
1739
- const toolsRunning = message.tools.some((tool) => tool.status === "running");
1740
- const waiting = message.status === "streaming" && body.length === 0 && !toolsRunning;
1847
+ const waiting = message.status === "streaming" && body.length === 0 && message.tools.length === 0;
1741
1848
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-assistant-message flex gap-2", children: [
1742
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: [
1743
1850
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Avatar, { ...avatarUrl ? { src: avatarUrl } : {}, name: assistantName }),
@@ -1747,12 +1854,12 @@ var MessageBubble = (0, import_react8.memo)(function MessageBubble2({
1747
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,
1748
1855
  showChoices ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Choices, { options: options ?? [], onPick: onChoose, ...onRequestInput ? { onSomethingElse: onRequestInput } : {}, disabled: busy }) : null,
1749
1856
  showToolActivity ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolActivityList, { tools: message.tools, ...renderTool ? { renderTool } : {} }) : null,
1750
- waiting ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Thinking, {}) : null
1857
+ waiting ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Thinking, { delayed: true }) : null
1751
1858
  ] })
1752
1859
  ] });
1753
1860
  });
1754
1861
  function MessageCopyButton({ text }) {
1755
- const [copied, setCopied] = (0, import_react8.useState)(false);
1862
+ const [copied, setCopied] = (0, import_react9.useState)(false);
1756
1863
  const copy = async () => {
1757
1864
  try {
1758
1865
  await navigator.clipboard.writeText(text);
@@ -1776,8 +1883,8 @@ function TypingDots() {
1776
1883
  ))
1777
1884
  ] });
1778
1885
  }
1779
- function Thinking() {
1780
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "frankie-skeleton", role: "status", "aria-label": "Thinking", children: [
1886
+ 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: [
1781
1888
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "62%" } }),
1782
1889
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "92%" } }),
1783
1890
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "frankie-skeleton-line", style: { width: "48%" } })
@@ -1801,14 +1908,14 @@ function ChatPanel({
1801
1908
  const { config, configError, loading } = useFrankie();
1802
1909
  const theme = useFrankieTheme();
1803
1910
  const { messages, busy, restoring, error, send, stop, reset } = useFrankieChat();
1804
- const scrollRef = (0, import_react9.useRef)(null);
1805
- const atBottomRef = (0, import_react9.useRef)(true);
1911
+ const scrollRef = (0, import_react10.useRef)(null);
1912
+ const atBottomRef = (0, import_react10.useRef)(true);
1806
1913
  const features = config?.features;
1807
1914
  const pickerModels = features?.modelPicker.enabled ? features.modelPicker.models : [];
1808
- const [model, setModel] = (0, import_react9.useState)(void 0);
1809
- const composerFocus = (0, import_react9.useRef)(null);
1915
+ const [model, setModel] = (0, import_react10.useState)(void 0);
1916
+ const composerFocus = (0, import_react10.useRef)(null);
1810
1917
  const focusComposer = () => composerFocus.current?.();
1811
- (0, import_react9.useEffect)(() => {
1918
+ (0, import_react10.useEffect)(() => {
1812
1919
  const node = scrollRef.current;
1813
1920
  if (!node) return;
1814
1921
  const onScroll = () => {
@@ -1817,7 +1924,7 @@ function ChatPanel({
1817
1924
  node.addEventListener("scroll", onScroll, { passive: true });
1818
1925
  return () => node.removeEventListener("scroll", onScroll);
1819
1926
  }, []);
1820
- (0, import_react9.useEffect)(() => {
1927
+ (0, import_react10.useEffect)(() => {
1821
1928
  const node = scrollRef.current;
1822
1929
  if (!node) return;
1823
1930
  if (messages.length === 0) {
@@ -1828,7 +1935,7 @@ function ChatPanel({
1828
1935
  node.scrollTop = node.scrollHeight;
1829
1936
  }, [messages]);
1830
1937
  const name = config?.branding.name ?? "Assistant";
1831
- const mode = resolveMode(theme?.mode);
1938
+ const mode = useResolvedMode(theme?.mode);
1832
1939
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1833
1940
  Card,
1834
1941
  {
@@ -1906,19 +2013,21 @@ function FrankieWidget({
1906
2013
  open: controlledOpen,
1907
2014
  onOpenChange,
1908
2015
  renderLauncher,
2016
+ launcher = true,
2017
+ avoidBottomBars = true,
1909
2018
  ...panelProps
1910
2019
  }) {
1911
- const { config, injectStyles } = useFrankie();
2020
+ const { config, injectStyles, themeReady } = useFrankie();
1912
2021
  const theme = useFrankieTheme();
1913
- const rootRef = (0, import_react10.useRef)(null);
2022
+ const rootRef = (0, import_react11.useRef)(null);
1914
2023
  const stylesReady = useStylesReady(rootRef, void 0, injectStyles);
1915
- const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react10.useState)(defaultOpen);
2024
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react11.useState)(defaultOpen);
1916
2025
  const open = controlledOpen ?? uncontrolledOpen;
1917
2026
  const setOpen = (next) => {
1918
2027
  if (controlledOpen === void 0) setUncontrolledOpen(next);
1919
2028
  onOpenChange?.(next);
1920
2029
  };
1921
- (0, import_react10.useEffect)(() => {
2030
+ (0, import_react11.useEffect)(() => {
1922
2031
  if (!open) return;
1923
2032
  const onKeyDown = (event) => {
1924
2033
  if (event.key === "Escape") setOpen(false);
@@ -1926,20 +2035,60 @@ function FrankieWidget({
1926
2035
  window.addEventListener("keydown", onKeyDown);
1927
2036
  return () => window.removeEventListener("keydown", onKeyDown);
1928
2037
  }, [open]);
2038
+ (0, import_react11.useEffect)(() => {
2039
+ const onClick = (event) => {
2040
+ const target = event.target instanceof Element ? event.target.closest("[data-frankie-open]") : null;
2041
+ if (!target || rootRef.current?.contains(target)) return;
2042
+ if (target instanceof HTMLAnchorElement && !target.getAttribute("href")?.startsWith("#")) event.preventDefault();
2043
+ setOpen(true);
2044
+ };
2045
+ document.addEventListener("click", onClick);
2046
+ return () => document.removeEventListener("click", onClick);
2047
+ }, []);
2048
+ const [lift, setLift] = (0, import_react11.useState)(0);
2049
+ (0, import_react11.useEffect)(() => {
2050
+ if (!avoidBottomBars || typeof window === "undefined") {
2051
+ setLift(0);
2052
+ return;
2053
+ }
2054
+ let frame = 0;
2055
+ let last = 0;
2056
+ const measure = () => {
2057
+ frame = 0;
2058
+ last = Date.now();
2059
+ setLift(bottomObstruction(rootRef.current, position, offset));
2060
+ };
2061
+ const schedule = () => {
2062
+ if (frame) return;
2063
+ const wait = Math.max(0, 400 - (Date.now() - last));
2064
+ frame = window.setTimeout(() => requestAnimationFrame(measure), wait);
2065
+ };
2066
+ schedule();
2067
+ window.addEventListener("resize", schedule);
2068
+ const observer = typeof MutationObserver === "function" ? new MutationObserver((records) => {
2069
+ if (records.some((record) => !rootRef.current?.contains(record.target))) schedule();
2070
+ }) : void 0;
2071
+ observer?.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class", "style"] });
2072
+ return () => {
2073
+ window.clearTimeout(frame);
2074
+ window.removeEventListener("resize", schedule);
2075
+ observer?.disconnect();
2076
+ };
2077
+ }, [avoidBottomBars, position, offset]);
1929
2078
  const label = config?.branding.launcherLabel ?? "Need a hand?";
1930
- const mode = resolveMode(theme?.mode);
2079
+ const mode = useResolvedMode(theme?.mode);
1931
2080
  const side = position === "bottom-right" ? { right: offset } : { left: offset };
1932
2081
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1933
2082
  "div",
1934
2083
  {
1935
2084
  ref: rootRef,
1936
2085
  className: cn("frankie-root frankie-widget", mode === "dark" && "dark"),
1937
- style: { ...themeToCssVars(theme), position: "fixed", bottom: offset, ...side, zIndex, pointerEvents: "none", ...stylesReady ? null : { opacity: 0 } },
2086
+ 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 } },
1938
2087
  "data-frankie-mode": mode,
1939
2088
  "data-frankie-styles": stylesReady ? "ready" : "pending",
1940
2089
  children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: cn("flex flex-col gap-3", position === "bottom-left" ? "items-start" : "items-end"), children: [
1941
- open ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { pointerEvents: "auto", maxHeight: "calc(100dvh - 100px)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatPanel, { ...panelProps, className: cn("frankie-widget-panel", panelProps.className), onClose: () => setOpen(false), autoFocus: true }) }) : null,
1942
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { pointerEvents: "auto" }, children: renderLauncher ? renderLauncher({ open, toggle: () => setOpen(!open), label }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
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)(
1943
2092
  Button,
1944
2093
  {
1945
2094
  size: "icon",
@@ -1950,27 +2099,27 @@ function FrankieWidget({
1950
2099
  title: label,
1951
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" })
1952
2101
  }
1953
- ) })
2102
+ ) }) : null
1954
2103
  ] })
1955
2104
  }
1956
2105
  );
1957
2106
  }
1958
2107
 
1959
2108
  // src/components/chat/FrankieInline.tsx
1960
- var import_react11 = require("react");
2109
+ var import_react12 = require("react");
1961
2110
  var import_jsx_runtime17 = require("react/jsx-runtime");
1962
2111
  function FrankieInline({ className, style, ...panelProps }) {
1963
- const { injectStyles } = useFrankie();
2112
+ const { injectStyles, themeReady } = useFrankie();
1964
2113
  const theme = useFrankieTheme();
1965
- const mode = resolveMode(theme?.mode);
1966
- const rootRef = (0, import_react11.useRef)(null);
2114
+ const mode = useResolvedMode(theme?.mode);
2115
+ const rootRef = (0, import_react12.useRef)(null);
1967
2116
  const stylesReady = useStylesReady(rootRef, void 0, injectStyles);
1968
2117
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1969
2118
  "div",
1970
2119
  {
1971
2120
  ref: rootRef,
1972
2121
  className: cn("frankie-root frankie-inline", mode === "dark" && "dark", className),
1973
- style: { ...themeToCssVars(theme), display: "flex", height: "100%", width: "100%", ...style, ...stylesReady ? null : { opacity: 0 } },
2122
+ style: { ...themeToCssVars(theme), display: "flex", height: "100%", width: "100%", ...style, ...stylesReady && themeReady ? null : { opacity: 0 } },
1974
2123
  "data-frankie-mode": mode,
1975
2124
  "data-frankie-styles": stylesReady ? "ready" : "pending",
1976
2125
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatPanel, { ...panelProps, fill: true })
@@ -1979,8 +2128,49 @@ function FrankieInline({ className, style, ...panelProps }) {
1979
2128
  }
1980
2129
 
1981
2130
  // src/components/chat/FrankieChatPage.tsx
1982
- var import_react12 = require("react");
2131
+ var import_react14 = require("react");
1983
2132
  var import_lucide_react9 = require("lucide-react");
2133
+
2134
+ // src/lib/viewport-fill.ts
2135
+ var import_react13 = require("react");
2136
+ function useViewportFill(ref, enabled) {
2137
+ const [fill, setFill] = (0, import_react13.useState)(0);
2138
+ (0, import_react13.useEffect)(() => {
2139
+ if (!enabled || typeof window === "undefined") {
2140
+ setFill(0);
2141
+ return;
2142
+ }
2143
+ let timer = 0;
2144
+ let last = 0;
2145
+ const measure = () => {
2146
+ timer = 0;
2147
+ last = Date.now();
2148
+ const node = ref.current;
2149
+ if (!node) return;
2150
+ const top = node.getBoundingClientRect().top + window.scrollY;
2151
+ const lift = bottomObstruction(node, "bottom-right", 0);
2152
+ setFill(Math.max(0, Math.round(window.innerHeight - top - lift)));
2153
+ };
2154
+ const schedule = () => {
2155
+ if (timer) return;
2156
+ timer = window.setTimeout(() => requestAnimationFrame(measure), Math.max(0, 300 - (Date.now() - last)));
2157
+ };
2158
+ measure();
2159
+ window.addEventListener("resize", schedule);
2160
+ const observer = typeof MutationObserver === "function" ? new MutationObserver((records) => {
2161
+ if (records.some((record) => !ref.current?.contains(record.target))) schedule();
2162
+ }) : void 0;
2163
+ observer?.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class", "style"] });
2164
+ return () => {
2165
+ window.clearTimeout(timer);
2166
+ window.removeEventListener("resize", schedule);
2167
+ observer?.disconnect();
2168
+ };
2169
+ }, [ref, enabled]);
2170
+ return fill;
2171
+ }
2172
+
2173
+ // src/components/chat/FrankieChatPage.tsx
1984
2174
  var import_jsx_runtime18 = require("react/jsx-runtime");
1985
2175
  function groupByDate(items) {
1986
2176
  const now = /* @__PURE__ */ new Date();
@@ -2000,29 +2190,30 @@ function groupByDate(items) {
2000
2190
  return buckets.filter((bucket) => bucket.items.length);
2001
2191
  }
2002
2192
  function useHistoryState() {
2003
- const [conversations, setConversations] = (0, import_react12.useState)([]);
2004
- const [historyError, setHistoryError] = (0, import_react12.useState)("");
2005
- const [historyLoading, setHistoryLoading] = (0, import_react12.useState)(false);
2006
- const [query, setQuery] = (0, import_react12.useState)("");
2193
+ const [conversations, setConversations] = (0, import_react14.useState)([]);
2194
+ const [historyError, setHistoryError] = (0, import_react14.useState)("");
2195
+ const [historyLoading, setHistoryLoading] = (0, import_react14.useState)(false);
2196
+ const [query, setQuery] = (0, import_react14.useState)("");
2007
2197
  return { conversations, setConversations, historyError, setHistoryError, historyLoading, setHistoryLoading, query, setQuery };
2008
2198
  }
2009
2199
  function PageChrome({ showHistory, navigation, currentId, onSelect, onNew, history: state, ...panel }) {
2010
- const { client, config } = useFrankie();
2200
+ const { client, config, themeReady } = useFrankie();
2011
2201
  const { busy, messages } = useFrankieChat();
2012
2202
  const theme = useFrankieTheme();
2203
+ const mode = useResolvedMode(theme?.mode);
2013
2204
  const { conversations, setConversations, historyError, setHistoryError, historyLoading, setHistoryLoading, query, setQuery } = state;
2014
- const [drawerOpen, setDrawerOpen] = (0, import_react12.useState)(false);
2015
- const [collapsed, setCollapsed] = (0, import_react12.useState)(() => {
2205
+ const [drawerOpen, setDrawerOpen] = (0, import_react14.useState)(false);
2206
+ const [collapsed, setCollapsed] = (0, import_react14.useState)(() => {
2016
2207
  try {
2017
2208
  return window.localStorage.getItem("frankie.history-collapsed") === "1";
2018
2209
  } catch {
2019
2210
  return false;
2020
2211
  }
2021
2212
  });
2022
- const dialog = (0, import_react12.useRef)(null);
2023
- const menu = (0, import_react12.useRef)(null);
2024
- const requestVersion = (0, import_react12.useRef)(0);
2025
- const refresh = (0, import_react12.useCallback)(async () => {
2213
+ const dialog = (0, import_react14.useRef)(null);
2214
+ const menu = (0, import_react14.useRef)(null);
2215
+ const requestVersion = (0, import_react14.useRef)(0);
2216
+ const refresh = (0, import_react14.useCallback)(async () => {
2026
2217
  if (!showHistory || !config || config.allowAnonymous) {
2027
2218
  setHistoryError("");
2028
2219
  return;
@@ -2043,19 +2234,19 @@ function PageChrome({ showHistory, navigation, currentId, onSelect, onNew, histo
2043
2234
  if (version === requestVersion.current) setHistoryLoading(false);
2044
2235
  }
2045
2236
  }, [client, showHistory, config?.allowAnonymous, setConversations, setHistoryError, setHistoryLoading]);
2046
- (0, import_react12.useEffect)(() => {
2237
+ (0, import_react14.useEffect)(() => {
2047
2238
  if (!busy) void refresh();
2048
2239
  return () => {
2049
2240
  requestVersion.current++;
2050
2241
  };
2051
2242
  }, [refresh, busy]);
2052
- (0, import_react12.useEffect)(() => {
2243
+ (0, import_react14.useEffect)(() => {
2053
2244
  try {
2054
2245
  window.localStorage.setItem("frankie.history-collapsed", collapsed ? "1" : "0");
2055
2246
  } catch {
2056
2247
  }
2057
2248
  }, [collapsed]);
2058
- (0, import_react12.useEffect)(() => {
2249
+ (0, import_react14.useEffect)(() => {
2059
2250
  const node = dialog.current;
2060
2251
  if (drawerOpen) {
2061
2252
  node?.showModal?.();
@@ -2102,7 +2293,7 @@ function PageChrome({ showHistory, navigation, currentId, onSelect, onNew, histo
2102
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,
2103
2294
  navigation ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "frankie-host-navigation", children: navigation }) : null
2104
2295
  ] });
2105
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-page-shell" + (resolveMode(theme?.mode) === "dark" ? " dark" : ""), style: themeToCssVars(theme), children: [
2296
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "frankie-page-shell" + (mode === "dark" ? " dark" : ""), style: { ...themeToCssVars(theme), ...themeReady ? null : { opacity: 0 } }, children: [
2106
2297
  showHistory ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("aside", { className: "frankie-history-desktop" + (collapsed ? " frankie-history-collapsed" : ""), children: [
2107
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 }) }),
2108
2299
  collapsed ? null : history
@@ -2139,13 +2330,14 @@ function PageChrome({ showHistory, navigation, currentId, onSelect, onNew, histo
2139
2330
  }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("aside", { children: history }) }) : null
2140
2331
  ] });
2141
2332
  }
2142
- function FrankieChatPage({ className, style, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus, showHistory = true, navigation, ...provider }) {
2143
- const [id, setId] = (0, import_react12.useState)(() => provider.conversationId ?? crypto.randomUUID());
2333
+ function FrankieChatPage({ className, style, header, footer, emptyState, renderMessage, renderTool, placeholder, autoFocus, showHistory = true, navigation, fillViewport = true, ...provider }) {
2334
+ const [id, setId] = (0, import_react14.useState)(() => provider.conversationId ?? crypto.randomUUID());
2144
2335
  const onNew = () => setId(crypto.randomUUID());
2145
2336
  const history = useHistoryState();
2146
- const pageRef = (0, import_react12.useRef)(null);
2337
+ const pageRef = (0, import_react14.useRef)(null);
2147
2338
  const stylesReady = useStylesReady(pageRef, void 0, provider.injectStyles);
2148
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { ref: pageRef, className: ["frankie-root", "frankie-chat-page", className].filter(Boolean).join(" "), style: { height: "100%", minHeight: "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 }) }) });
2339
+ 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 }) }) });
2149
2341
  }
2150
2342
 
2151
2343
  // src/components/chat/SuggestedPrompts.tsx
@@ -2217,6 +2409,7 @@ function Separator({ className }) {
2217
2409
  themeToCssVars,
2218
2410
  useFrankie,
2219
2411
  useFrankieChat,
2220
- useFrankieTheme
2412
+ useFrankieTheme,
2413
+ useResolvedMode
2221
2414
  });
2222
2415
  //# sourceMappingURL=index.cjs.map