@noodleseed/assistant 1.25.1 → 1.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +54 -20
  2. package/dist/{app-view-element-BNkQab1B.d.ts → app-view-element-C_ATXseu.d.ts} +1 -1
  3. package/dist/{app-view-element-DhuiNW_x.d.cts → app-view-element-CiFVNIke.d.cts} +1 -1
  4. package/dist/app-view.cjs +5 -5
  5. package/dist/app-view.cjs.map +1 -1
  6. package/dist/app-view.d.cts +3 -3
  7. package/dist/app-view.d.ts +3 -3
  8. package/dist/app-view.js +2 -2
  9. package/dist/{appearance-B6vSg8Ub.d.cts → appearance-C24W6BRj.d.cts} +7 -3
  10. package/dist/{appearance-B6vSg8Ub.d.ts → appearance-C24W6BRj.d.ts} +7 -3
  11. package/dist/{chunk-5TYS2Q6S.js → chunk-5NBHHNI3.js} +2 -2
  12. package/dist/{chunk-7BQHW37I.js → chunk-FNXAVRL5.js} +7 -1
  13. package/dist/{chunk-7BQHW37I.js.map → chunk-FNXAVRL5.js.map} +1 -1
  14. package/dist/{chunk-FJYPE4GC.js → chunk-OZVDL77T.js} +713 -122
  15. package/dist/chunk-OZVDL77T.js.map +1 -0
  16. package/dist/{chunk-CF2SCDLF.js → chunk-XKTUXFGX.js} +6 -6
  17. package/dist/chunk-XKTUXFGX.js.map +1 -0
  18. package/dist/{client-BkogON2A.d.ts → client-BheCOERq.d.ts} +51 -2
  19. package/dist/{client-C07ppTU_.d.cts → client-BiMRVxjs.d.cts} +51 -2
  20. package/dist/client.cjs.map +1 -1
  21. package/dist/client.d.cts +2 -2
  22. package/dist/client.d.ts +2 -2
  23. package/dist/client.js +1 -1
  24. package/dist/embed.global.js +171 -89
  25. package/dist/index.cjs +720 -124
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +6 -53
  28. package/dist/index.d.ts +6 -53
  29. package/dist/index.js +3 -3
  30. package/dist/react/client.cjs.map +1 -1
  31. package/dist/react/client.d.cts +2 -2
  32. package/dist/react/client.d.ts +2 -2
  33. package/dist/react/client.js +1 -1
  34. package/dist/react.cjs +720 -124
  35. package/dist/react.cjs.map +1 -1
  36. package/dist/react.d.cts +4 -4
  37. package/dist/react.d.ts +4 -4
  38. package/dist/react.js +4 -4
  39. package/dist/server.d.cts +1 -1
  40. package/dist/server.d.ts +1 -1
  41. package/package.json +1 -1
  42. package/dist/chunk-CF2SCDLF.js.map +0 -1
  43. package/dist/chunk-FJYPE4GC.js.map +0 -1
  44. /package/dist/{chunk-5TYS2Q6S.js.map → chunk-5NBHHNI3.js.map} +0 -0
@@ -2,18 +2,22 @@ import {
2
2
  ASSISTANT_APP_VIEW_CSS,
3
3
  mountAssistantApp,
4
4
  updateAssistantAppTheme
5
- } from "./chunk-CF2SCDLF.js";
5
+ } from "./chunk-XKTUXFGX.js";
6
6
  import {
7
7
  AssistantClientError,
8
8
  copyAssistantModelContext,
9
9
  copyAssistantPageContext,
10
10
  createAssistantClient,
11
+ publicConfigurationUrl,
11
12
  sessionSourceKey
12
- } from "./chunk-7BQHW37I.js";
13
+ } from "./chunk-FNXAVRL5.js";
14
+ import {
15
+ external_exports
16
+ } from "./chunk-3YYTUJPJ.js";
13
17
 
14
18
  // src/appearance.ts
15
19
  var common = {
16
- fontFamily: "inherit",
20
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
17
21
  monoFontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
18
22
  baseFontSize: 15,
19
23
  messageFontSize: 15,
@@ -24,7 +28,7 @@ var common = {
24
28
  buttonRadius: 999,
25
29
  launcherRadius: 999,
26
30
  spacing: 8,
27
- backdropBlur: 18,
31
+ backdropBlur: 6,
28
32
  motionScale: 1
29
33
  };
30
34
  var DEFAULT_APPEARANCE = {
@@ -44,7 +48,7 @@ var DEFAULT_APPEARANCE = {
44
48
  accent: "#C2410C",
45
49
  accentText: "#FFFFFF",
46
50
  link: "#9A3412",
47
- divider: "#E4E4E7",
51
+ divider: "rgba(0, 0, 0, 0.1)",
48
52
  focus: "#C2410C",
49
53
  success: "#16835D",
50
54
  warning: "#A45B00",
@@ -52,7 +56,7 @@ var DEFAULT_APPEARANCE = {
52
56
  overlay: "#18181B66",
53
57
  code: "#F1F1F3",
54
58
  widgetFrame: "#E4E4E7",
55
- shadow: "0 4px 16px rgba(0, 0, 0, 0.06), 0 24px 70px rgba(0, 0, 0, 0.10)"
59
+ shadow: "0 4px 16px rgba(0, 0, 0, 0.06)"
56
60
  },
57
61
  dark: {
58
62
  ...common,
@@ -67,7 +71,7 @@ var DEFAULT_APPEARANCE = {
67
71
  accent: "#FB923C",
68
72
  accentText: "#1C0A02",
69
73
  link: "#FDBA74",
70
- divider: "#292524",
74
+ divider: "rgba(255, 255, 255, 0.1)",
71
75
  focus: "#FB923C",
72
76
  success: "#58C69A",
73
77
  warning: "#F2B45F",
@@ -75,15 +79,15 @@ var DEFAULT_APPEARANCE = {
75
79
  overlay: "#00000099",
76
80
  code: "#26262C",
77
81
  widgetFrame: "#34343B",
78
- shadow: "0 8px 32px rgba(0, 0, 0, 0.48)"
82
+ shadow: "0 8px 32px rgba(0, 0, 0, 0.4)"
79
83
  }
80
84
  },
81
85
  layout: {
82
86
  mode: "floating",
83
- position: "bottom-right",
84
- panelWidth: 520,
85
- panelMinHeight: 540,
86
- panelMaxHeight: 820,
87
+ position: "bottom-center",
88
+ panelWidth: 970,
89
+ panelMinHeight: 0,
90
+ panelMaxHeight: 1025,
87
91
  edgeOffset: 20,
88
92
  zIndex: 2147483e3,
89
93
  density: "comfortable",
@@ -96,11 +100,13 @@ var DEFAULT_APPEARANCE = {
96
100
  showLauncher: true,
97
101
  showHeader: true,
98
102
  showAvatars: true,
99
- showTimestamps: false
103
+ showTimestamps: false,
104
+ showPoweredBy: true
100
105
  },
101
106
  labels: {
102
- welcomeHeading: "How can I help?",
107
+ welcomeHeading: "",
103
108
  welcomeMessage: "",
109
+ launcherPlaceholder: "Chat with us",
104
110
  composerPlaceholder: "Ask a question\u2026",
105
111
  thinking: "Thinking",
106
112
  send: "Send",
@@ -134,11 +140,12 @@ var DEFAULT_APPEARANCE = {
134
140
  },
135
141
  presentation: {
136
142
  panel: {
137
- surface: "glass",
143
+ surface: "solid",
138
144
  elevation: "soft",
139
145
  border: "subtle"
140
146
  },
141
147
  launcher: {
148
+ style: "pill",
142
149
  icon: "brand-mark",
143
150
  size: "md",
144
151
  status: "none",
@@ -148,7 +155,11 @@ var DEFAULT_APPEARANCE = {
148
155
  composer: { leadingIcon: "none", sendIcon: "arrow-up", shape: "pill" },
149
156
  messages: { userStyle: "bubble", assistantStyle: "plain" }
150
157
  },
151
- suggestedPrompts: [],
158
+ suggestedPrompts: [
159
+ "What products do you have?",
160
+ "Tell me about your business",
161
+ "How can I get in touch?"
162
+ ],
152
163
  locale: "en",
153
164
  direction: "auto"
154
165
  };
@@ -164,7 +175,7 @@ function resolveAppearance(input = {}) {
164
175
  mark: themedAsset(branding?.mark)
165
176
  },
166
177
  theme: {
167
- defaultMode: branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,
178
+ defaultMode: assistant?.theme ?? branding?.colorScheme ?? DEFAULT_APPEARANCE.theme.defaultMode,
168
179
  light: resolveTheme("light", branding),
169
180
  dark: resolveTheme("dark", branding)
170
181
  },
@@ -175,9 +186,17 @@ function resolveAppearance(input = {}) {
175
186
  ...assistant?.layout?.edgeOffset === void 0 ? {} : { edgeOffset: boundedNumber(assistant.layout.edgeOffset, 0, 96) }
176
187
  },
177
188
  behavior: { ...DEFAULT_APPEARANCE.behavior, ...assistant?.behavior },
178
- labels: { ...DEFAULT_APPEARANCE.labels, ...assistant?.labels },
189
+ labels: {
190
+ ...DEFAULT_APPEARANCE.labels,
191
+ ...branding?.name ? { launcherPlaceholder: `Chat with ${branding.name}` } : {},
192
+ ...assistant?.labels
193
+ },
179
194
  presentation: resolvePresentation(assistant?.presentation),
180
- suggestedPrompts: assistant?.suggestedPrompts ?? DEFAULT_APPEARANCE.suggestedPrompts,
195
+ suggestedPrompts: assistant?.suggestedPrompts ?? (branding?.name ? [
196
+ "What products do you have?",
197
+ `Tell me about ${branding.name}`,
198
+ "How can I get in touch?"
199
+ ] : DEFAULT_APPEARANCE.suggestedPrompts),
181
200
  ...assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {},
182
201
  ...assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {},
183
202
  locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,
@@ -1199,11 +1218,11 @@ function createDOMPurify() {
1199
1218
  const originalDocument = document2;
1200
1219
  const currentScript = originalDocument.currentScript;
1201
1220
  window2.DocumentFragment;
1202
- const HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap;
1221
+ const HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element2 = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap;
1203
1222
  _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap;
1204
1223
  window2.HTMLFormElement;
1205
1224
  const DOMParser = window2.DOMParser, trustedTypes = window2.trustedTypes;
1206
- const ElementPrototype = Element.prototype;
1225
+ const ElementPrototype = Element2.prototype;
1207
1226
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
1208
1227
  const remove = lookupGetter(ElementPrototype, "remove");
1209
1228
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
@@ -3853,19 +3872,40 @@ function queryRequired(root, selector) {
3853
3872
  if (!element) throw new Error(`assistant renderer is missing ${selector}`);
3854
3873
  return element;
3855
3874
  }
3856
- function assistantElementMarkup(appearance, open, styles) {
3875
+ function assistantElementMarkup(appearance, styles) {
3857
3876
  return `${styles}
3858
- <button class="launcher" type="button" aria-label="${escapeAttribute(appearance.labels.open)}" aria-controls="assistant-panel" aria-expanded="${String(open)}"><slot name="launcher-icon"></slot><span class="visually-hidden" data-session-status aria-live="polite" hidden></span></button>
3877
+ <div class="launcher">
3878
+ <slot name="launcher-icon"></slot>
3879
+ <span class="launcher-loader" aria-hidden="true"></span>
3880
+ <button class="launcher-trigger" type="button" aria-label="${escapeAttribute(appearance.labels.open)}" aria-controls="assistant-launcher-form" aria-expanded="false">
3881
+ <span class="launcher-label">${escapeAttribute(appearance.labels.launcherPlaceholder)}</span>
3882
+ <span class="launcher-arrow" aria-hidden="true"></span>
3883
+ </button>
3884
+ <form class="launcher-form" id="assistant-launcher-form" aria-hidden="true" autocomplete="off">
3885
+ <input class="launcher-input" type="text" aria-label="${escapeAttribute(appearance.labels.launcherPlaceholder)}" placeholder="${escapeAttribute(appearance.labels.launcherPlaceholder)}" tabindex="-1">
3886
+ <button class="launcher-send" type="submit" aria-label="${escapeAttribute(appearance.labels.send)}"></button>
3887
+ </form>
3888
+ <span class="visually-hidden" data-session-status aria-live="polite" hidden></span>
3889
+ </div>
3859
3890
  <section class="panel" id="assistant-panel" role="dialog" aria-label="${escapeAttribute(appearance.brand.name)}">
3860
3891
  <header><slot name="header-leading"></slot><img class="brand-logo" alt=""><strong></strong><slot name="header-actions"></slot><button class="close" type="button" aria-label="${escapeAttribute(appearance.labels.close)}"></button></header>
3861
3892
  <div class="welcome"><slot name="empty-state"></slot></div>
3862
- <div class="suggested-prompts"></div>
3863
3893
  <div class="messages-region">
3864
3894
  <div class="messages" aria-live="polite"></div>
3865
3895
  <button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
3866
3896
  </div>
3867
- <form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
3897
+ <div class="input-section">
3898
+ <div class="suggested-prompts"></div>
3899
+ <form class="composer"><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
3900
+ </div>
3868
3901
  <nav class="legal" aria-label="Legal"></nav>
3902
+ <div class="powered-by-row">
3903
+ <a class="powered-by" href="https://noodleseed.com" target="_blank" rel="noopener noreferrer">
3904
+ <span>Powered by</span>
3905
+ <span class="powered-by-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="16" height="16" rx="8" fill="currentColor" fill-opacity="0.12"></rect><path d="M8.58023 12.8485C6.27833 12.8463 4.41315 11.0141 4.42117 8.75681L4.43588 4.61714L8.66254 4.62118C10.9644 4.62339 12.8296 6.45561 12.8216 8.71287C12.8135 10.9975 10.9128 12.8507 8.58023 12.8485Z" fill="currentColor"></path><path d="M8.82627 4.76869C11.1282 4.7709 12.9933 6.60312 12.9853 8.86038L12.9706 13L8.74395 12.996C6.44206 12.9938 4.57687 11.1616 4.5849 8.90432C4.59302 6.6197 6.49364 4.76646 8.82627 4.76869Z" fill="currentColor"></path><ellipse cx="3.69536" cy="3.68106" rx="0.695363" ry="0.681056" fill="currentColor"></ellipse></svg></span>
3906
+ <span class="powered-by-name">Noodle Seed</span>
3907
+ </a>
3908
+ </div>
3869
3909
  <slot name="conversation-footer"></slot>
3870
3910
  </section>`;
3871
3911
  }
@@ -3884,6 +3924,230 @@ function appendLegalLinks(legal, appearance) {
3884
3924
  }
3885
3925
  }
3886
3926
 
3927
+ // src/element-theme-resolution.ts
3928
+ function resolveAssistantTheme(input) {
3929
+ if (input.configured === "light" || input.configured === "dark") return input.configured;
3930
+ const hostMode = resolveHostTheme(input.host, input.media);
3931
+ return input.configured === "invert" ? opposite(hostMode) : hostMode;
3932
+ }
3933
+ function resolveHostTheme(host, media) {
3934
+ const view = host.ownerDocument.defaultView;
3935
+ for (let node = host.parentElement; node; node = node.parentElement) {
3936
+ const declared = declaredTheme(node);
3937
+ if (declared) return declared;
3938
+ const computed = computedTheme(view?.getComputedStyle(node).colorScheme);
3939
+ if (computed) return computed;
3940
+ }
3941
+ return media?.matches ? "dark" : "light";
3942
+ }
3943
+ function computedTheme(colorScheme) {
3944
+ const modes = colorScheme?.split(/\s+/) ?? [];
3945
+ if (modes.includes("dark") && !modes.includes("light")) return "dark";
3946
+ if (modes.includes("light") && !modes.includes("dark")) return "light";
3947
+ return void 0;
3948
+ }
3949
+ function declaredTheme(element) {
3950
+ const value = element.getAttribute("data-theme") ?? element.getAttribute("data-color-scheme") ?? element.getAttribute("data-mode");
3951
+ if (value === "dark" || value === "light") return value;
3952
+ if (element.classList.contains("dark")) return "dark";
3953
+ if (element.classList.contains("light")) return "light";
3954
+ return void 0;
3955
+ }
3956
+ function opposite(mode) {
3957
+ return mode === "dark" ? "light" : "dark";
3958
+ }
3959
+
3960
+ // src/element-host-environment-controller.ts
3961
+ var AssistantElementHostEnvironmentController = class {
3962
+ #host;
3963
+ #appearance;
3964
+ #applyTheme;
3965
+ #close;
3966
+ #media;
3967
+ #themeObserver;
3968
+ constructor(options) {
3969
+ this.#host = options.host;
3970
+ this.#appearance = options.appearance;
3971
+ this.#applyTheme = options.applyTheme;
3972
+ this.#close = options.close;
3973
+ }
3974
+ get media() {
3975
+ return this.#media;
3976
+ }
3977
+ resolvedTheme() {
3978
+ return resolveAssistantTheme({
3979
+ host: this.#host,
3980
+ configured: this.#host.getAttribute("theme") ?? this.#appearance().theme.defaultMode,
3981
+ ...this.#media ? { media: this.#media } : {}
3982
+ });
3983
+ }
3984
+ connect() {
3985
+ this.disconnect();
3986
+ this.#media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
3987
+ this.#media?.addEventListener("change", this.#applyTheme);
3988
+ this.#themeObserver = new MutationObserver(this.#applyTheme);
3989
+ for (let node = this.#host.parentElement; node; node = node.parentElement) {
3990
+ this.#themeObserver.observe(node, {
3991
+ attributes: true,
3992
+ attributeFilter: ["class", "data-theme", "data-color-scheme", "data-mode", "style"]
3993
+ });
3994
+ }
3995
+ document.addEventListener("keydown", this.#handleDocumentKeydown);
3996
+ document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
3997
+ }
3998
+ disconnect() {
3999
+ this.#media?.removeEventListener("change", this.#applyTheme);
4000
+ this.#media = void 0;
4001
+ this.#themeObserver?.disconnect();
4002
+ this.#themeObserver = void 0;
4003
+ document.removeEventListener("keydown", this.#handleDocumentKeydown);
4004
+ document.removeEventListener("pointerdown", this.#handleDocumentPointerDown);
4005
+ }
4006
+ #handleDocumentKeydown = (event) => {
4007
+ if (event.key === "Escape" && this.#host.hasAttribute("open") && this.#appearance().behavior.closeOnEscape) {
4008
+ this.#close();
4009
+ }
4010
+ };
4011
+ #handleDocumentPointerDown = (event) => {
4012
+ if (this.#host.hasAttribute("open") && this.#appearance().behavior.closeOnOutsideClick && !event.composedPath().includes(this.#host)) {
4013
+ this.#close();
4014
+ }
4015
+ };
4016
+ };
4017
+
4018
+ // src/element-launcher-controller.ts
4019
+ var AssistantElementLauncherController = class {
4020
+ #host;
4021
+ #appearance;
4022
+ #openPanel;
4023
+ #sendMessage;
4024
+ #root;
4025
+ constructor(options) {
4026
+ this.#host = options.host;
4027
+ this.#appearance = options.appearance;
4028
+ this.#openPanel = options.openPanel;
4029
+ this.#sendMessage = options.sendMessage;
4030
+ }
4031
+ connect(root) {
4032
+ this.disconnect();
4033
+ this.#root = root;
4034
+ queryRequired(root, ".launcher").addEventListener(
4035
+ "click",
4036
+ this.#handleLauncherClick
4037
+ );
4038
+ queryRequired(root, ".launcher-trigger").addEventListener(
4039
+ "click",
4040
+ this.#handleTrigger
4041
+ );
4042
+ queryRequired(root, ".launcher-form").addEventListener(
4043
+ "submit",
4044
+ this.#handleSubmit
4045
+ );
4046
+ queryRequired(root, ".launcher-input").addEventListener(
4047
+ "keydown",
4048
+ this.#handleInputKeydown
4049
+ );
4050
+ document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
4051
+ this.sync();
4052
+ }
4053
+ disconnect() {
4054
+ document.removeEventListener("pointerdown", this.#handleDocumentPointerDown);
4055
+ this.#root = void 0;
4056
+ }
4057
+ sync() {
4058
+ const root = this.#root;
4059
+ if (!root) return;
4060
+ const appearance = this.#appearance();
4061
+ const style = appearance.presentation.launcher.style;
4062
+ this.#host.dataset.launcherStyle = style;
4063
+ const trigger = queryRequired(root, ".launcher-trigger");
4064
+ const label = queryRequired(root, ".launcher-label");
4065
+ const input = queryRequired(root, ".launcher-input");
4066
+ label.textContent = appearance.labels.launcherPlaceholder;
4067
+ input.placeholder = appearance.labels.launcherPlaceholder;
4068
+ input.setAttribute("aria-label", appearance.labels.launcherPlaceholder);
4069
+ trigger.setAttribute("aria-label", appearance.labels.open);
4070
+ queryRequired(root, ".launcher-send").setAttribute(
4071
+ "aria-label",
4072
+ appearance.labels.send
4073
+ );
4074
+ queryRequired(root, ".launcher").hidden = !appearance.behavior.showLauncher;
4075
+ queryRequired(root, ".powered-by-row").hidden = !appearance.behavior.showPoweredBy;
4076
+ if (style === "bubble" || this.#host.hasAttribute("open")) this.collapse(true);
4077
+ }
4078
+ collapse(force = false) {
4079
+ const root = this.#root;
4080
+ if (!root) return;
4081
+ const input = queryRequired(root, ".launcher-input");
4082
+ if (!force && input.value.trim()) return;
4083
+ this.#host.removeAttribute("launcher-expanded");
4084
+ const form = queryRequired(root, ".launcher-form");
4085
+ const trigger = queryRequired(root, ".launcher-trigger");
4086
+ form.setAttribute("aria-hidden", "true");
4087
+ trigger.setAttribute("aria-expanded", "false");
4088
+ input.tabIndex = -1;
4089
+ input.blur();
4090
+ }
4091
+ focusTrigger() {
4092
+ this.#root?.querySelector(".launcher-trigger")?.focus();
4093
+ }
4094
+ #expand() {
4095
+ const root = this.#root;
4096
+ if (!root || this.#appearance().presentation.launcher.style === "bubble") return;
4097
+ this.#host.setAttribute("launcher-expanded", "");
4098
+ const form = queryRequired(root, ".launcher-form");
4099
+ const trigger = queryRequired(root, ".launcher-trigger");
4100
+ const input = queryRequired(root, ".launcher-input");
4101
+ form.setAttribute("aria-hidden", "false");
4102
+ trigger.setAttribute("aria-expanded", "true");
4103
+ input.tabIndex = 0;
4104
+ requestAnimationFrame(() => {
4105
+ if (this.#host.hasAttribute("launcher-expanded")) input.focus();
4106
+ });
4107
+ }
4108
+ #handleTrigger = () => {
4109
+ if (this.#appearance().presentation.launcher.style === "bubble") {
4110
+ this.#openPanel();
4111
+ return;
4112
+ }
4113
+ this.#expand();
4114
+ };
4115
+ #handleLauncherClick = (event) => {
4116
+ if (event.composedPath().some(
4117
+ (target) => target instanceof Element && target.matches(".launcher-trigger, .launcher-form")
4118
+ )) {
4119
+ return;
4120
+ }
4121
+ this.#handleTrigger();
4122
+ };
4123
+ #handleSubmit = (event) => {
4124
+ event.preventDefault();
4125
+ const input = this.#root?.querySelector(".launcher-input");
4126
+ const message = input?.value.trim() ?? "";
4127
+ if (input) input.value = "";
4128
+ this.#openPanel();
4129
+ if (message) this.#sendMessage(message);
4130
+ };
4131
+ #handleInputKeydown = (event) => {
4132
+ if (event.key === "Enter" && !event.isComposing) {
4133
+ event.preventDefault();
4134
+ this.#root?.querySelector(".launcher-form")?.requestSubmit();
4135
+ return;
4136
+ }
4137
+ if (event.key !== "Escape") return;
4138
+ event.preventDefault();
4139
+ event.stopPropagation();
4140
+ const input = this.#root?.querySelector(".launcher-input");
4141
+ if (input) input.value = "";
4142
+ this.collapse(true);
4143
+ this.focusTrigger();
4144
+ };
4145
+ #handleDocumentPointerDown = (event) => {
4146
+ if (event.composedPath().includes(this.#host)) return;
4147
+ this.collapse();
4148
+ };
4149
+ };
4150
+
3887
4151
  // src/element-page-context-controller.ts
3888
4152
  var AssistantElementPageContextController = class {
3889
4153
  #snapshot;
@@ -3937,10 +4201,12 @@ var AssistantElementPresentationGate = class {
3937
4201
  syncOpenState() {
3938
4202
  const open = this.#host.hasAttribute("open");
3939
4203
  const presentationReady = this.#host.hasAttribute("data-presentation-ready");
3940
- const launcher = this.#host.shadowRoot?.querySelector(".launcher");
3941
- launcher?.setAttribute("aria-expanded", String(open && presentationReady));
3942
- launcher?.setAttribute("aria-busy", String(open && !presentationReady));
3943
- if (launcher) launcher.disabled = open && !presentationReady;
4204
+ const publicConfigurationLoading = this.#host.hasAttribute("data-public-configuration-loading");
4205
+ const presentationBlocked = !presentationReady && (open || publicConfigurationLoading);
4206
+ const launcher = this.#host.shadowRoot?.querySelector(".launcher-trigger");
4207
+ launcher?.setAttribute("aria-busy", String(presentationBlocked));
4208
+ if (launcher) launcher.disabled = presentationBlocked;
4209
+ this.#host.shadowRoot?.querySelector(".panel")?.setAttribute("aria-hidden", String(!(open && presentationReady)));
3944
4210
  if (open && this.#host.isConnected) this.#primeSession();
3945
4211
  }
3946
4212
  reveal() {
@@ -3951,6 +4217,244 @@ var AssistantElementPresentationGate = class {
3951
4217
  }
3952
4218
  };
3953
4219
 
4220
+ // src/assistant-configuration-schema.ts
4221
+ var hexColorSchema = external_exports.string().regex(/^#[0-9A-Fa-f]{6}$/);
4222
+ var resolvedBorderColorSchema = external_exports.union([
4223
+ hexColorSchema,
4224
+ external_exports.string().max(64).refine(isBoundedRgbaColor, "must be a six-digit hex or bounded rgba color")
4225
+ ]);
4226
+ var browserAssetUrlSchema = external_exports.string().trim().url().refine(isSecureBrowserAssetUrl, "must use https (http is allowed only for loopback testing)");
4227
+ var httpsUrlSchema = external_exports.string().trim().url().refine(isHttpsUrl, "must use https");
4228
+ var brandAssetSchema = external_exports.object({
4229
+ uri: browserAssetUrlSchema,
4230
+ darkUri: browserAssetUrlSchema.optional(),
4231
+ alt: external_exports.string().trim().min(1).max(240)
4232
+ }).strict();
4233
+ var brandThemeSchema = external_exports.object({
4234
+ surface: hexColorSchema.optional(),
4235
+ surfaceRaised: hexColorSchema.optional(),
4236
+ surfaceMuted: hexColorSchema.optional(),
4237
+ text: hexColorSchema.optional(),
4238
+ textMuted: hexColorSchema.optional(),
4239
+ accent: hexColorSchema.optional(),
4240
+ accentText: hexColorSchema.optional(),
4241
+ link: hexColorSchema.optional(),
4242
+ border: resolvedBorderColorSchema.optional(),
4243
+ borderStrong: resolvedBorderColorSchema.optional(),
4244
+ focus: hexColorSchema.optional(),
4245
+ success: hexColorSchema.optional(),
4246
+ warning: hexColorSchema.optional(),
4247
+ danger: hexColorSchema.optional(),
4248
+ code: hexColorSchema.optional()
4249
+ }).strict();
4250
+ var brandingSchema = external_exports.object({
4251
+ name: external_exports.string().trim().min(1).max(160).optional(),
4252
+ accent: hexColorSchema.optional(),
4253
+ surface: hexColorSchema.optional(),
4254
+ surfaceDark: hexColorSchema.optional(),
4255
+ logo: brandAssetSchema.optional(),
4256
+ mark: brandAssetSchema.optional(),
4257
+ avatar: brandAssetSchema.optional(),
4258
+ theme: external_exports.object({ light: brandThemeSchema.optional(), dark: brandThemeSchema.optional() }).strict().optional(),
4259
+ radius: external_exports.enum(["none", "sm", "md", "lg"]).optional(),
4260
+ density: external_exports.enum(["compact", "comfortable"]).optional(),
4261
+ typography: external_exports.enum(["system", "serif", "mono"]).optional(),
4262
+ colorScheme: external_exports.enum(["auto", "light", "dark"]).optional()
4263
+ }).strict();
4264
+ var labelsSchema = external_exports.object({
4265
+ welcomeHeading: external_exports.string().trim().min(1).max(160).optional(),
4266
+ welcomeMessage: external_exports.string().max(1e3).optional(),
4267
+ launcherPlaceholder: external_exports.string().trim().min(1).max(160).optional(),
4268
+ composerPlaceholder: external_exports.string().trim().min(1).max(160).optional(),
4269
+ thinking: external_exports.string().trim().min(1).max(80).optional(),
4270
+ send: external_exports.string().trim().min(1).max(80).optional(),
4271
+ stop: external_exports.string().trim().min(1).max(80).optional(),
4272
+ close: external_exports.string().trim().min(1).max(80).optional(),
4273
+ open: external_exports.string().trim().min(1).max(80).optional(),
4274
+ confirm: external_exports.string().trim().min(1).max(80).optional(),
4275
+ decline: external_exports.string().trim().min(1).max(80).optional(),
4276
+ cancel: external_exports.string().trim().min(1).max(80).optional(),
4277
+ confirmationHeading: external_exports.string().trim().min(1).max(120).optional(),
4278
+ additionalDetails: external_exports.string().trim().min(1).max(120).optional(),
4279
+ redacted: external_exports.string().trim().min(1).max(120).optional(),
4280
+ completed: external_exports.string().trim().min(1).max(80).optional(),
4281
+ stopped: external_exports.string().trim().min(1).max(80).optional(),
4282
+ copy: external_exports.string().trim().min(1).max(80).optional(),
4283
+ newMessages: external_exports.string().trim().min(1).max(80).optional(),
4284
+ reconnect: external_exports.string().trim().min(1).max(80).optional(),
4285
+ newConversation: external_exports.string().trim().min(1).max(80).optional(),
4286
+ retry: external_exports.string().trim().min(1).max(80).optional(),
4287
+ unavailable: external_exports.string().trim().min(1).max(240).optional(),
4288
+ sessionExpired: external_exports.string().trim().min(1).max(240).optional(),
4289
+ sessionIdle: external_exports.string().trim().min(1).max(120).optional(),
4290
+ sessionLoading: external_exports.string().trim().min(1).max(120).optional(),
4291
+ sessionReady: external_exports.string().trim().min(1).max(120).optional(),
4292
+ sessionError: external_exports.string().trim().min(1).max(120).optional(),
4293
+ signInHeading: external_exports.string().trim().min(1).max(120).optional(),
4294
+ signInBody: external_exports.string().max(240).optional(),
4295
+ signInAction: external_exports.string().trim().min(1).max(80).optional(),
4296
+ signUpAction: external_exports.string().trim().min(1).max(80).optional()
4297
+ }).strict();
4298
+ var presentationSchema = external_exports.object({
4299
+ panel: external_exports.object({
4300
+ surface: external_exports.enum(["solid", "glass"]).optional(),
4301
+ elevation: external_exports.enum(["soft", "dramatic"]).optional(),
4302
+ border: external_exports.enum(["subtle", "strong"]).optional(),
4303
+ radius: external_exports.number().int().min(0).max(64).optional()
4304
+ }).strict().optional(),
4305
+ launcher: external_exports.object({
4306
+ style: external_exports.enum(["pill", "bubble"]).optional(),
4307
+ icon: external_exports.enum(["brand-mark", "chat", "none"]).optional(),
4308
+ size: external_exports.enum(["md", "lg"]).optional(),
4309
+ status: external_exports.enum(["none", "session"]).optional(),
4310
+ effect: external_exports.enum(["none", "pulse"]).optional()
4311
+ }).strict().optional(),
4312
+ header: external_exports.object({
4313
+ mark: external_exports.enum(["none", "brand-mark", "status"]).optional(),
4314
+ badge: external_exports.object({
4315
+ text: external_exports.string().trim().min(1).max(80),
4316
+ tone: external_exports.enum(["neutral", "success", "warning", "danger"]).optional(),
4317
+ indicator: external_exports.boolean().optional()
4318
+ }).strict().optional()
4319
+ }).strict().optional(),
4320
+ composer: external_exports.object({
4321
+ leadingIcon: external_exports.enum(["none", "brand-mark"]).optional(),
4322
+ sendIcon: external_exports.enum(["arrow-up", "paper-plane"]).optional(),
4323
+ shape: external_exports.enum(["rounded", "pill"]).optional()
4324
+ }).strict().optional(),
4325
+ messages: external_exports.object({
4326
+ userStyle: external_exports.enum(["bubble", "accent"]).optional(),
4327
+ assistantStyle: external_exports.enum(["plain", "bubble"]).optional()
4328
+ }).strict().optional()
4329
+ }).strict();
4330
+ var assistantUiSchema = external_exports.object({
4331
+ theme: external_exports.enum(["auto", "light", "dark", "invert"]).optional(),
4332
+ layout: external_exports.object({
4333
+ mode: external_exports.enum(["floating", "inline", "drawer"]).optional(),
4334
+ position: external_exports.enum(["bottom-left", "bottom-center", "bottom-right"]).optional(),
4335
+ panelWidth: external_exports.number().int().min(280).max(1200).optional(),
4336
+ panelMinHeight: external_exports.number().int().min(240).max(1600).optional(),
4337
+ panelMaxHeight: external_exports.number().int().min(320).max(2400).optional(),
4338
+ edgeOffset: external_exports.number().int().min(0).max(96).optional(),
4339
+ zIndex: external_exports.number().int().min(0).max(2147483647).optional(),
4340
+ density: external_exports.enum(["compact", "comfortable"]).optional(),
4341
+ mobileFullscreen: external_exports.boolean().optional()
4342
+ }).strict().optional(),
4343
+ behavior: external_exports.object({
4344
+ startOpen: external_exports.boolean().optional(),
4345
+ closeOnEscape: external_exports.boolean().optional(),
4346
+ closeOnOutsideClick: external_exports.boolean().optional(),
4347
+ showLauncher: external_exports.boolean().optional(),
4348
+ showHeader: external_exports.boolean().optional(),
4349
+ showAvatars: external_exports.boolean().optional(),
4350
+ showTimestamps: external_exports.boolean().optional(),
4351
+ showPoweredBy: external_exports.boolean().optional()
4352
+ }).strict().optional(),
4353
+ labels: labelsSchema.optional(),
4354
+ presentation: presentationSchema.optional(),
4355
+ suggestedPrompts: external_exports.array(external_exports.string().trim().min(1).max(240)).max(8).optional(),
4356
+ privacyUrl: httpsUrlSchema.optional(),
4357
+ termsUrl: httpsUrlSchema.optional(),
4358
+ locale: external_exports.string().trim().min(2).max(35).optional(),
4359
+ direction: external_exports.enum(["ltr", "rtl", "auto"]).optional()
4360
+ }).strict();
4361
+ var assistantConfigurationSchema = external_exports.object({ branding: brandingSchema.optional(), assistant: assistantUiSchema.optional() }).strict();
4362
+ function parseAssistantConfiguration(value) {
4363
+ const parsed = assistantConfigurationSchema.safeParse(value);
4364
+ return parsed.success ? parsed.data : void 0;
4365
+ }
4366
+ function isHttpsUrl(value) {
4367
+ try {
4368
+ return new URL(value).protocol === "https:";
4369
+ } catch {
4370
+ return false;
4371
+ }
4372
+ }
4373
+ function isSecureBrowserAssetUrl(value) {
4374
+ try {
4375
+ const url = new URL(value);
4376
+ if (url.protocol === "https:") return true;
4377
+ if (url.protocol !== "http:") return false;
4378
+ return url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
4379
+ } catch {
4380
+ return false;
4381
+ }
4382
+ }
4383
+ function isBoundedRgbaColor(value) {
4384
+ const match = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0(?:\.\d{1,6})?|1(?:\.0{1,6})?)\s*\)$/.exec(
4385
+ value
4386
+ );
4387
+ if (match === null) return false;
4388
+ return match.slice(1, 4).every((channel) => Number(channel) <= 255);
4389
+ }
4390
+
4391
+ // src/element-public-configuration-controller.ts
4392
+ var AssistantElementPublicConfigurationController = class {
4393
+ #source;
4394
+ #apply;
4395
+ #loadingChanged;
4396
+ #generation = 0;
4397
+ #bootstrap;
4398
+ #abort;
4399
+ constructor(source, apply2, loadingChanged) {
4400
+ this.#source = source;
4401
+ this.#apply = apply2;
4402
+ this.#loadingChanged = loadingChanged;
4403
+ }
4404
+ connect() {
4405
+ this.#restart();
4406
+ }
4407
+ refresh() {
4408
+ this.#restart();
4409
+ }
4410
+ disconnect() {
4411
+ this.#generation += 1;
4412
+ this.#abort?.abort();
4413
+ this.#abort = void 0;
4414
+ this.#bootstrap = void 0;
4415
+ }
4416
+ #restart() {
4417
+ this.disconnect();
4418
+ this.#prime();
4419
+ }
4420
+ #prime() {
4421
+ const source = this.#source();
4422
+ if (!source.embedId || this.#bootstrap) return;
4423
+ const generation = this.#generation;
4424
+ const abort = new AbortController();
4425
+ this.#abort = abort;
4426
+ const fetcher = source.fetch ?? ((input, init) => globalThis.fetch(input, init));
4427
+ this.#loadingChanged(true);
4428
+ const bootstrap = Promise.resolve().then(
4429
+ () => fetcher(publicConfigurationUrl(source.serviceUrl, source.embedId), {
4430
+ method: "GET",
4431
+ headers: { accept: "application/json" },
4432
+ credentials: "omit",
4433
+ cache: "no-cache",
4434
+ signal: abort.signal
4435
+ })
4436
+ ).then(async (response) => {
4437
+ if (!response.ok) return;
4438
+ const value = await response.json();
4439
+ if (generation !== this.#generation || !isRecord2(value)) {
4440
+ return;
4441
+ }
4442
+ const configuration = parseAssistantConfiguration(value.configuration);
4443
+ if (configuration !== void 0) this.#apply(configuration);
4444
+ }).catch(() => void 0).finally(() => {
4445
+ if (generation === this.#generation) this.#loadingChanged(false);
4446
+ if (this.#bootstrap === bootstrap) {
4447
+ this.#bootstrap = void 0;
4448
+ this.#abort = void 0;
4449
+ }
4450
+ });
4451
+ this.#bootstrap = bootstrap;
4452
+ }
4453
+ };
4454
+ function isRecord2(value) {
4455
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4456
+ }
4457
+
3954
4458
  // src/element-scroll-controller.ts
3955
4459
  var AssistantElementScrollController = class {
3956
4460
  #region;
@@ -4057,44 +4561,69 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
4057
4561
  *, *::before, *::after { box-sizing: border-box; }
4058
4562
  .visually-hidden { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; border: 0 !important; }
4059
4563
  .visually-hidden[hidden] { display: none !important; }
4060
- :host { color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); -webkit-font-smoothing: antialiased; }
4061
- :host([data-mode="floating"]) { position: fixed; bottom: 20px; right: 20px; }
4062
- :host([data-mode="floating"][data-position="bottom-left"]) { right: auto; left: 20px; }
4564
+ :host { --ns-assistant-halo-launcher-action: #f4f4f5; --ns-assistant-halo-launcher-action-hover: #e4e4e7; --ns-assistant-halo-launcher-border: rgba(0,0,0,.04); --ns-assistant-halo-launcher-shadow: 0 1px 8px rgba(0,0,0,.04); --ns-assistant-halo-launcher-shadow-hover: 0 2px 12px rgba(0,0,0,.06); --ns-assistant-halo-send-button: #e4e4e7; --ns-assistant-halo-send-button-text: #09090b; box-sizing: border-box; color-scheme: light dark; font-family: var(--ns-assistant-font-family, var(--ns-assistant-default-font-family)); font-size: var(--ns-assistant-base-font-size, var(--ns-assistant-default-base-font-size)); line-height: var(--ns-assistant-line-height, var(--ns-assistant-default-line-height)); z-index: var(--ns-assistant-z-index, var(--ns-assistant-default-z-index)); -webkit-font-smoothing: antialiased; }
4565
+ :host([data-theme="dark"]) { --ns-assistant-halo-launcher-action: #3f3f46; --ns-assistant-halo-launcher-action-hover: #52525b; --ns-assistant-halo-launcher-border: rgba(255,255,255,.1); --ns-assistant-halo-launcher-shadow: 0 4px 20px rgba(0,0,0,.3); --ns-assistant-halo-launcher-shadow-hover: 0 6px 24px rgba(0,0,0,.4); --ns-assistant-halo-send-button: #3f3f46; --ns-assistant-halo-send-button-text: #fff; }
4566
+ :host([data-mode="floating"]) { position: fixed; }
4567
+ :host([data-mode="floating"][open]) { width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), 100vw); }
4063
4568
  button { font: inherit; }
4064
4569
  button, textarea, input, select { -webkit-tap-highlight-color: transparent; }
4065
- .launcher { display: grid; place-items: center; width: 48px; height: 48px; border: 1px solid var(--ns-assistant-launcher-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; color: var(--ns-assistant-launcher-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-launcher, var(--ns-assistant-panel, var(--ns-assistant-default-panel))); box-shadow: 0 8px 28px rgba(0,0,0,.14); cursor: pointer; transition: transform .24s cubic-bezier(.25,1,.5,1), box-shadow .2s ease; }
4066
- .launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
4067
- .launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
4068
- .panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; isolation: isolate; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
4570
+ .launcher { display: flex; align-items: center; justify-content: center; gap: 12px; width: max-content; min-height: 44px; padding: 10px 14px; color: var(--ns-assistant-launcher-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-launcher, color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 50%, transparent)); border: 1px solid var(--ns-assistant-launcher-border, var(--ns-assistant-halo-launcher-border)); border-radius: 999px; box-shadow: var(--ns-assistant-halo-launcher-shadow), -6px 0 18px color-mix(in srgb, var(--ns-assistant-accent, var(--ns-assistant-default-accent)) 20%, transparent), 6px 0 18px color-mix(in srgb, var(--ns-assistant-accent, var(--ns-assistant-default-accent)) 20%, transparent), 0 0 40px color-mix(in srgb, var(--ns-assistant-accent, var(--ns-assistant-default-accent)) 10%, transparent); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); transition: width .5s cubic-bezier(.25,1,.5,1), height .5s cubic-bezier(.25,1,.5,1), padding .5s cubic-bezier(.25,1,.5,1), gap .35s cubic-bezier(.25,1,.5,1), transform .6s cubic-bezier(.25,1,.5,1), background-color .3s ease, box-shadow .3s ease; }
4571
+ :host([data-presentation-ready]) .launcher { padding: 10px 12px; }
4572
+ .launcher[hidden] { display: none; }
4573
+ .launcher:hover { transform: scale(1.02); box-shadow: var(--ns-assistant-halo-launcher-shadow-hover), -6px 0 18px color-mix(in srgb, var(--ns-assistant-accent, var(--ns-assistant-default-accent)) 20%, transparent), 6px 0 18px color-mix(in srgb, var(--ns-assistant-accent, var(--ns-assistant-default-accent)) 20%, transparent); }
4574
+ .launcher-trigger, .launcher-form { min-width: 0; margin: 0; padding: 0; border: 0; background: transparent; font: inherit; }
4575
+ .launcher-trigger { display: flex; align-items: center; gap: 12px; min-height: 28px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); cursor: text; }
4576
+ .launcher-label { padding-left: 6px; white-space: nowrap; font-size: 15px; line-height: 20px; }
4577
+ .launcher-arrow, .launcher-send { position: relative; display: grid; width: 28px; height: 28px; flex: 0 0 28px; place-items: center; border: 0; border-radius: 50%; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-launcher-action, var(--ns-assistant-halo-launcher-action)); cursor: pointer; }
4578
+ .launcher-arrow:hover, .launcher-send:hover { background: var(--ns-assistant-launcher-action-hover, var(--ns-assistant-halo-launcher-action-hover)); }
4579
+ .launcher-arrow::before, .launcher-send::before { content: ''; width: 16px; height: 16px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4580
+ .launcher-form { display: none; flex: 1; align-items: center; gap: 12px; opacity: 0; pointer-events: none; }
4581
+ .launcher-input { width: 100%; min-width: 0; height: 28px; padding: 0 0 0 6px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 0; outline: 0; box-shadow: none; appearance: none; font: inherit; font-size: 16px; line-height: 20px; }
4582
+ .launcher-input::placeholder { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
4583
+ :host([launcher-expanded]) .launcher { width: min(400px, calc(100vw - 40px)); justify-content: flex-start; }
4584
+ :host([launcher-expanded]) .launcher-trigger { display: none; }
4585
+ :host([launcher-expanded]) .launcher-form { display: flex; opacity: 1; pointer-events: auto; }
4586
+ :host([data-launcher-style="bubble"]) .launcher { gap: 0; min-height: 0; padding: 6px; cursor: pointer; }
4587
+ :host([data-launcher-style="bubble"]) .launcher-trigger { position: absolute; inset: 0; display: block; width: 100%; height: 100%; cursor: pointer; }
4588
+ :host([data-launcher-style="bubble"]) .launcher-label, :host([data-launcher-style="bubble"]) .launcher-arrow, :host([data-launcher-style="bubble"]) .launcher-form { display: none; }
4589
+ :host([data-launcher-style="bubble"]) .launcher-visual { width: 32px; height: 32px; flex-basis: 32px; }
4590
+ .launcher-loader { display: none; width: 16px; height: 16px; flex: 0 0 16px; border: 2px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-top-color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); border-radius: 50%; animation: halo-spin .8s linear infinite; }
4591
+ :host([data-session-state="loading"]:not([data-presentation-ready])) .launcher-loader, :host([data-public-configuration-loading]:not([data-presentation-ready])) .launcher-loader { display: block; }
4592
+ :host([data-session-state="loading"]:not([data-presentation-ready])) .launcher > :not(.launcher-loader):not([data-session-status]), :host([data-public-configuration-loading]:not([data-presentation-ready])) .launcher > :not(.launcher-loader):not([data-session-status]) { display: none; }
4593
+ .panel { display: none; flex-direction: column; width: 100%; max-width: 970px; height: min(85dvh, var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100dvh - 40px)); min-height: min(var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)), calc(100dvh - 40px)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100dvh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom center; isolation: isolate; animation: halo-panel-in .3s ease both; }
4594
+ :host([data-mode="floating"][open]) .panel { width: calc(100% - 40px); margin-inline: 20px; }
4069
4595
  :host([open][data-presentation-ready]) .panel { display: flex; }
4070
4596
  .panel { position: relative; }
4071
4597
  :host([open][data-presentation-ready]) .launcher { display: none; }
4072
4598
  :host([open]:not([data-presentation-ready])) .launcher { cursor: progress; opacity: .72; transform: none; }
4073
- header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))) 78%, transparent); }
4599
+ header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 16px 20px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); }
4074
4600
  header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: 0; }
4075
4601
  .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
4076
4602
  .close, .send { display: grid; place-items: center; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }
4077
- .close { position: relative; width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; transition: background .15s ease, color .15s ease, transform .15s ease; }
4078
- .close::before { content: ''; width: 18px; height: 18px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4603
+ .close { position: relative; width: 44px; height: 44px; margin: -6px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; transition: background .15s ease, color .15s ease, transform .15s ease; }
4604
+ .close::before { content: ''; width: 20px; height: 20px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4079
4605
  .close:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }
4080
4606
  .close:active { transform: scale(.96); }
4081
- .welcome { flex: 0 0 auto; padding: 30px 22px 18px; }
4607
+ .welcome { flex: 0 0 auto; padding: 24px 20px 8px; }
4082
4608
  .welcome h2 { margin: 0; font-size: 1.35em; line-height: 1.25; letter-spacing: 0; }
4083
4609
  .welcome p { max-width: 42ch; margin: 7px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
4084
- :host([has-messages]) .welcome, :host([has-messages]) .suggested-prompts { display: none; }
4085
- .suggested-prompts { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; padding: 0 20px 16px; }
4610
+ .welcome:has(.empty-state[hidden]) { display: none; }
4611
+ :host([has-messages]) .welcome { display: none; }
4612
+ .input-section { flex: 0 0 auto; padding: 8px 16px 16px; }
4613
+ .suggested-prompts { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
4086
4614
  .suggested-prompts:empty { display: none; }
4087
- .suggested-prompts button { min-height: 44px; padding: 8px 14px; color: var(--ns-assistant-suggestion-text, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text))); background: var(--ns-assistant-suggestion, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 58%, transparent)); border: 1px solid var(--ns-assistant-suggestion-border, color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) 82%, transparent)); border-radius: 999px; cursor: pointer; font-size: .86em; transition: background .2s ease, color .2s ease, border-color .2s ease, transform .2s ease; }
4088
- .suggested-prompts button:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); transform: translateY(-1px); }
4615
+ .suggested-prompts button { position: relative; display: inline-flex; align-items: center; padding: 6px 12px; color: var(--ns-assistant-suggestion-text, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text))); background: var(--ns-assistant-suggestion, transparent); border: 1px solid var(--ns-assistant-suggestion-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; cursor: pointer; font-size: 12px; white-space: nowrap; transition: background .2s ease, color .2s ease; }
4616
+ .suggested-prompts button::before { content: ''; position: absolute; inset: -6px -2px; }
4617
+ .suggested-prompts button:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }
4089
4618
  .messages-region { position: relative; display: flex; flex: 1 1 auto; min-height: 0; overflow: hidden; }
4090
4619
  .messages-region::before, .messages-region::after { content: ''; position: absolute; right: 0; left: 0; z-index: 1; height: 18px; pointer-events: none; opacity: 0; transition: opacity .18s ease; }
4091
4620
  .messages-region::before { top: 0; background: linear-gradient(to bottom, color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 92%, transparent), transparent); }
4092
4621
  .messages-region::after { bottom: 0; background: linear-gradient(to top, color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 92%, transparent), transparent); }
4093
4622
  .messages-region[data-can-scroll-up]::before, .messages-region[data-can-scroll-down]::after { opacity: 1; }
4094
- .messages { flex: 1 1 auto; width: 100%; min-height: 0; padding: 18px 20px 24px; overflow-y: auto; background: var(--ns-assistant-canvas, transparent); overscroll-behavior: contain; scroll-behavior: smooth; }
4623
+ .messages { flex: 1 1 auto; width: 100%; min-height: 0; padding: 16px 20px; overflow-y: auto; background: var(--ns-assistant-canvas, transparent); overscroll-behavior: contain; scroll-behavior: smooth; }
4095
4624
  .messages::-webkit-scrollbar { width: 6px; }
4096
4625
  .messages::-webkit-scrollbar-thumb { background: var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; }
4097
- .message { width: fit-content; max-width: 88%; margin: 0 0 14px; padding: 0; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: transparent; white-space: pre-wrap; animation: halo-message-in .2s ease both; }
4626
+ .message { width: fit-content; max-width: 88%; margin: 0 0 12px; padding: 0; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: transparent; white-space: pre-wrap; animation: halo-message-in .2s ease both; }
4098
4627
  .message > span, .message > .markdown { overflow-wrap: anywhere; }
4099
4628
  .message .avatar { float: left; width: 24px; height: 24px; margin-right: 9px; border-radius: 50%; object-fit: cover; }
4100
4629
  .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; line-height: 1.2; }
@@ -4107,7 +4636,7 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
4107
4636
  .new-messages { position: absolute; left: 50%; bottom: 14px; z-index: 2; width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-secondary-button-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-secondary-button, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 92%, transparent)); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); box-shadow: 0 8px 24px rgba(0,0,0,.12); transform: translateX(-50%); cursor: pointer; }
4108
4637
  .new-messages::before { content: ''; display: block; width: 18px; height: 18px; margin: auto; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4109
4638
  .message.assistant { max-width: 100%; color: var(--ns-assistant-assistant-message-text, inherit); background: var(--ns-assistant-assistant-message, transparent); border: 1px solid var(--ns-assistant-assistant-message-border, transparent); }
4110
- .message.user { display: grid; max-width: 85%; justify-items: start; gap: 3px; margin-left: auto; padding: 10px 16px 8px; color: var(--ns-assistant-user-message-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-user-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-user-message-border, transparent); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); font-size: .94em; }
4639
+ .message.user { display: grid; max-width: 85%; justify-items: start; gap: 3px; margin-left: auto; padding: 10px 16px; color: var(--ns-assistant-user-message-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-user-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-user-message-border, transparent); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); font-size: 14px; }
4111
4640
  .message.user time { margin-top: 0; }
4112
4641
  .markdown { white-space: normal; }
4113
4642
  .markdown p { margin: 0 0 8px; }
@@ -4157,31 +4686,39 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
4157
4686
  .input-request input:focus-visible, .input-request select:focus-visible { border-color: var(--ns-assistant-focus, var(--ns-assistant-default-focus)); box-shadow: 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
4158
4687
  .input-request .proposal-actions { margin-top: 2px; }
4159
4688
  ${ASSISTANT_APP_VIEW_CSS}
4160
- form { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height: 56px; margin: 8px 16px 16px; padding: 6px 6px 6px 16px; color: var(--ns-assistant-composer-text, inherit); border: 1px solid var(--ns-assistant-composer-border, color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) 86%, transparent)); border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); background: var(--ns-assistant-composer, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 92%, transparent)); box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.035); transition: border-color .15s ease, box-shadow .15s ease; }
4161
- form:focus-within { box-shadow: inset 0 0 0 1px var(--ns-assistant-focus, var(--ns-assistant-default-focus)), 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
4689
+ .composer { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height: 44px; margin: 0; padding: 8px 8px 8px 16px; color: var(--ns-assistant-composer-text, inherit); border: 1px solid var(--ns-assistant-composer-border, transparent); border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); background: var(--ns-assistant-composer, var(--ns-assistant-input, var(--ns-assistant-default-input))); transition: border-color .15s ease, box-shadow .15s ease; }
4690
+ .composer:focus-within { border-color: var(--ns-assistant-focus, var(--ns-assistant-default-focus)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ns-assistant-focus, var(--ns-assistant-default-focus)) 32%, transparent); }
4162
4691
  textarea { flex: 1; min-height: 24px; max-height: 120px; resize: none; padding: 0; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 0; border-radius: 0; outline: 0; box-shadow: none; appearance: none; -webkit-appearance: none; font: inherit; font-size: 16px; line-height: 24px; }
4163
4692
  textarea::placeholder { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
4164
4693
  textarea:focus, textarea:focus-visible { outline: none; box-shadow: none; }
4165
4694
  button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }
4166
- .send { position: relative; display: block; width: 44px; height: 44px; flex: 0 0 44px; padding: 0; overflow: hidden; color: transparent; border-radius: 999px; background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); font-size: 0; line-height: 0; transition: transform .15s ease, background .15s ease; }
4167
- .send::before { content: ''; position: absolute; top: 50%; left: 50%; width: 17px; height: 17px; background: var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))); transform: translate(-50%, -50%); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4168
- .send:hover { transform: scale(1.05); background: var(--ns-assistant-hover, color-mix(in srgb, var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))) 88%, var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))) 12%)); }
4695
+ .send { position: relative; display: block; width: 44px; height: 44px; flex: 0 0 44px; margin: -8px; padding: 0; overflow: visible; color: var(--ns-assistant-primary-button-text, var(--ns-assistant-halo-send-button-text)); border-radius: 999px; background: transparent; font-size: 0; line-height: 0; }
4696
+ .send::after { content: ''; position: absolute; top: 50%; left: 50%; z-index: 0; width: 28px; height: 28px; border-radius: 50%; background: var(--ns-assistant-primary-button, var(--ns-assistant-halo-send-button)); transform: translate(-50%, -50%); }
4697
+ .send::before { content: ''; position: absolute; top: 50%; left: 50%; z-index: 1; width: 16px; height: 16px; background: currentColor; transform: translate(-50%, -50%); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
4698
+ .send:hover::after { background: var(--ns-assistant-hover, var(--ns-assistant-default-hover)); }
4169
4699
  :host([busy]) .send::before { width: 13px; height: 13px; border-radius: 3px; -webkit-mask: none; mask: none; }
4170
4700
  .send:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }
4171
- .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 9px; font-size: .75em; }
4701
+ .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 8px; font-size: .75em; }
4172
4702
  .legal:empty { display: none; }
4173
4703
  .legal a { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); text-underline-offset: 2px; }
4704
+ .powered-by-row { display: flex; flex: 0 0 auto; justify-content: center; padding-bottom: 12px; }
4705
+ .powered-by-row[hidden] { display: none; }
4706
+ .powered-by { display: inline-flex; align-items: center; gap: 6px; margin: 0 auto 12px; padding: 0 16px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: 11px; line-height: 1; text-decoration: none; opacity: .7; transition: opacity .12s ease, color .12s ease; }
4707
+ .powered-by:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); opacity: 1; }
4708
+ .powered-by-icon { display: inline-flex; width: 14px; height: 14px; }
4709
+ .powered-by-name { font-weight: 500; }
4174
4710
  ::slotted([slot="conversation-footer"]) { display: block; padding: 0 16px 12px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: 11px; text-align: center; }
4175
- @keyframes halo-panel-in { from { opacity: 0; transform: translateY(14px) scale(.985); } to { opacity: 1; transform: none; } }
4711
+ @keyframes halo-panel-in { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
4176
4712
  @keyframes halo-message-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
4177
4713
  @keyframes halo-shimmer { from { background-position: 100% center; } to { background-position: 0 center; } }
4178
4714
  @keyframes halo-caret-blink { 50% { opacity: 0; } }
4715
+ @keyframes halo-spin { to { transform: rotate(360deg); } }
4179
4716
  :host([data-density="compact"]) .welcome { padding: 20px 18px 12px; }
4180
- @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border: 0; border-radius: 0; } :host([mobile-fullscreen]) header { padding-top: max(12px, env(safe-area-inset-top)); padding-right: max(18px, env(safe-area-inset-right)); padding-left: max(18px, env(safe-area-inset-left)); } :host([mobile-fullscreen]) form { margin-right: max(16px, env(safe-area-inset-right)); margin-bottom: max(16px, env(safe-area-inset-bottom)); margin-left: max(16px, env(safe-area-inset-left)); } :host([mobile-fullscreen]) .legal, :host([mobile-fullscreen]) ::slotted([slot="conversation-footer"]) { padding-bottom: max(10px, env(safe-area-inset-bottom)); } }
4717
+ @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; width: 100vw; transform: none; } :host([mobile-fullscreen][open]) .panel { width: 100vw; max-width: none; height: 100dvh; min-height: 100dvh; max-height: 100dvh; margin: 0; border: 0; border-radius: 0; } :host([mobile-fullscreen]) header { padding-top: calc(16px + env(safe-area-inset-top)); padding-right: calc(20px + env(safe-area-inset-right)); padding-left: calc(20px + env(safe-area-inset-left)); } :host([mobile-fullscreen]) .messages { padding-right: calc(20px + env(safe-area-inset-right)); padding-left: calc(20px + env(safe-area-inset-left)); } :host([mobile-fullscreen]) .input-section { padding-right: calc(16px + env(safe-area-inset-right)); padding-bottom: calc(16px + env(safe-area-inset-bottom)); padding-left: calc(16px + env(safe-area-inset-left)); } :host([mobile-fullscreen]) .legal, :host([mobile-fullscreen]) ::slotted([slot="conversation-footer"]) { padding-bottom: max(10px, env(safe-area-inset-bottom)); } }
4181
4718
  @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } .messages { scroll-behavior: auto; } .message.assistant.streaming .markdown::after { animation: none; } }
4182
4719
  @media (forced-colors: active) { .message.thinking > span { color: CanvasText; background: none; } }
4183
4720
  @media (hover: none) { .message-copy { opacity: 1; } }
4184
- @media (max-width: 560px) { :host([data-mode="floating"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }
4721
+ @media (max-width: 560px) { :host([data-mode="floating"]:not([open])) { bottom: 20px; } :host([open]:not([mobile-fullscreen])) .panel { width: calc(100vw - 40px); max-height: calc(100dvh - 40px); } }
4185
4722
  </style>`;
4186
4723
 
4187
4724
  // src/host-appearance.ts
@@ -4290,6 +4827,7 @@ function syncAssistantPresentation(host, root, appearance, mode, sessionState) {
4290
4827
  host.dataset.panelSurface = presentation.panel.surface;
4291
4828
  host.dataset.panelElevation = presentation.panel.elevation;
4292
4829
  host.dataset.panelBorder = presentation.panel.border;
4830
+ host.dataset.launcherStyle = presentation.launcher.style;
4293
4831
  host.dataset.launcherEffect = presentation.launcher.effect;
4294
4832
  host.dataset.messageUserStyle = presentation.messages.userStyle;
4295
4833
  host.dataset.messageAssistantStyle = presentation.messages.assistantStyle;
@@ -4302,11 +4840,11 @@ function syncAssistantPresentation(host, root, appearance, mode, sessionState) {
4302
4840
  }
4303
4841
  host.style.setProperty(
4304
4842
  "--ns-assistant-presentation-launcher-size",
4305
- presentation.launcher.size === "lg" ? "56px" : "48px"
4843
+ presentation.launcher.size === "lg" ? "56px" : "44px"
4306
4844
  );
4307
4845
  host.style.setProperty(
4308
4846
  "--ns-assistant-presentation-panel-background",
4309
- presentation.panel.surface === "solid" ? "var(--ns-assistant-panel, var(--ns-assistant-default-panel))" : "color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 88%, transparent)"
4847
+ presentation.panel.surface === "solid" ? "var(--ns-assistant-panel, var(--ns-assistant-default-panel))" : "color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 50%, transparent)"
4310
4848
  );
4311
4849
  host.style.setProperty(
4312
4850
  "--ns-assistant-presentation-shadow",
@@ -4314,7 +4852,7 @@ function syncAssistantPresentation(host, root, appearance, mode, sessionState) {
4314
4852
  );
4315
4853
  host.style.setProperty(
4316
4854
  "--ns-assistant-presentation-border",
4317
- panelBorder(presentation.panel.border)
4855
+ panelBorder(presentation.panel.border, mode)
4318
4856
  );
4319
4857
  replaceFallback(root, "launcher-icon", [launcherVisual(appearance, mode, sessionState)]);
4320
4858
  const accessibleStatus = root.querySelector("[data-session-status]");
@@ -4327,7 +4865,7 @@ function syncAssistantPresentation(host, root, appearance, mode, sessionState) {
4327
4865
  replaceFallback(root, "empty-state", [emptyState(appearance)]);
4328
4866
  replaceFallback(root, "composer-leading", composerLeading(appearance, mode));
4329
4867
  replaceFallback(root, "conversation-footer", []);
4330
- const form = root.querySelector("form");
4868
+ const form = root.querySelector(".composer");
4331
4869
  if (form) form.dataset.shape = presentation.composer.shape;
4332
4870
  const send = root.querySelector(".send");
4333
4871
  if (send) send.dataset.icon = presentation.composer.sendIcon;
@@ -4347,18 +4885,21 @@ function panelShadow(elevation) {
4347
4885
  }
4348
4886
  return "var(--ns-assistant-default-shadow)";
4349
4887
  }
4350
- function panelBorder(border) {
4888
+ function panelBorder(border, mode) {
4351
4889
  if (border === "strong") {
4352
4890
  return "1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider))";
4353
4891
  }
4354
- return "1px solid color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) 74%, transparent)";
4892
+ const opacity = mode === "light" ? 60 : 100;
4893
+ return `1px solid color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) ${opacity}%, transparent)`;
4355
4894
  }
4356
4895
  function launcherVisual(appearance, mode, sessionState) {
4357
4896
  const launcher = appearance.presentation.launcher;
4358
4897
  const visual = document.createElement("span");
4359
4898
  visual.className = "launcher-visual";
4360
4899
  visual.setAttribute("aria-hidden", "true");
4361
- visual.append(icon(launcher.icon, appearance, mode, "launcher-glyph"));
4900
+ const visualKind = launcher.icon === "brand-mark" && !(appearance.brand.mark[mode] ?? appearance.brand.logo[mode]) ? launcher.style === "bubble" ? "chat" : "none" : launcher.icon;
4901
+ visual.hidden = visualKind === "none";
4902
+ visual.append(icon(visualKind, appearance, mode, "launcher-glyph"));
4362
4903
  if (launcher.status === "session") {
4363
4904
  const status = document.createElement("span");
4364
4905
  status.className = "launcher-status";
@@ -4408,9 +4949,12 @@ function headerBadge(appearance) {
4408
4949
  function emptyState(appearance) {
4409
4950
  const section = document.createElement("section");
4410
4951
  section.className = "empty-state";
4411
- const heading = document.createElement("h2");
4412
- heading.textContent = appearance.labels.welcomeHeading;
4413
- section.append(heading);
4952
+ section.hidden = !appearance.labels.welcomeHeading && !appearance.labels.welcomeMessage;
4953
+ if (appearance.labels.welcomeHeading) {
4954
+ const heading = document.createElement("h2");
4955
+ heading.textContent = appearance.labels.welcomeHeading;
4956
+ section.append(heading);
4957
+ }
4414
4958
  const description = appearance.labels.welcomeMessage;
4415
4959
  if (description) {
4416
4960
  const paragraph = document.createElement("p");
@@ -4437,7 +4981,7 @@ function toneIndicator(tone) {
4437
4981
  return indicator;
4438
4982
  }
4439
4983
  function icon(kind, appearance, mode, className) {
4440
- const mark = appearance.brand.mark[mode];
4984
+ const mark = appearance.brand.mark[mode] ?? appearance.brand.logo[mode];
4441
4985
  if (kind === "brand-mark" && mark) {
4442
4986
  const image = document.createElement("img");
4443
4987
  image.className = className;
@@ -4489,11 +5033,17 @@ function applyAssistantElementTheme(input) {
4489
5033
  var presentationStyles = `<style>
4490
5034
  :host([data-mode="floating"]) {
4491
5035
  bottom: var(--ns-assistant-edge-offset, var(--ns-assistant-default-edge-offset));
4492
- right: var(--ns-assistant-edge-offset, var(--ns-assistant-default-edge-offset));
5036
+ left: 50%;
5037
+ transform: translateX(-50%);
4493
5038
  }
4494
5039
  :host([data-mode="floating"][data-position="bottom-left"]) {
4495
- right: auto;
4496
5040
  left: var(--ns-assistant-edge-offset, var(--ns-assistant-default-edge-offset));
5041
+ transform: none;
5042
+ }
5043
+ :host([data-mode="floating"][data-position="bottom-right"]) {
5044
+ right: var(--ns-assistant-edge-offset, var(--ns-assistant-default-edge-offset));
5045
+ left: auto;
5046
+ transform: none;
4497
5047
  }
4498
5048
  .panel {
4499
5049
  background: var(--ns-assistant-panel-background, var(--ns-assistant-presentation-panel-background));
@@ -4510,22 +5060,26 @@ var presentationStyles = `<style>
4510
5060
 
4511
5061
  .launcher {
4512
5062
  position: relative;
4513
- width: var(--ns-assistant-launcher-size, var(--ns-assistant-presentation-launcher-size));
4514
- height: var(--ns-assistant-launcher-size, var(--ns-assistant-presentation-launcher-size));
4515
5063
  border-radius: var(--ns-assistant-launcher-radius, var(--ns-assistant-default-launcher-radius));
4516
5064
  isolation: isolate;
4517
5065
  }
5066
+ :host([data-launcher-style="bubble"]) .launcher {
5067
+ width: var(--ns-assistant-launcher-size, var(--ns-assistant-presentation-launcher-size));
5068
+ height: var(--ns-assistant-launcher-size, var(--ns-assistant-presentation-launcher-size));
5069
+ }
4518
5070
  :host([data-launcher-effect="pulse"]) .launcher {
4519
5071
  animation: assistant-launcher-pulse 2s ease-in-out infinite;
4520
5072
  }
4521
5073
  .launcher-visual {
4522
5074
  position: relative;
4523
5075
  display: grid;
4524
- width: 100%;
4525
- height: 100%;
5076
+ width: 28px;
5077
+ height: 28px;
5078
+ flex: 0 0 28px;
4526
5079
  place-items: center;
4527
5080
  border-radius: inherit;
4528
5081
  }
5082
+ .launcher-visual[hidden] { display: none; }
4529
5083
  .launcher-glyph, .composer-leading-glyph {
4530
5084
  display: block;
4531
5085
  width: 18px;
@@ -4553,10 +5107,28 @@ var presentationStyles = `<style>
4553
5107
  -webkit-mask: none;
4554
5108
  mask: none;
4555
5109
  }
5110
+ .launcher-visual .launcher-glyph:is(img) {
5111
+ width: 28px;
5112
+ height: 28px;
5113
+ border-radius: 50%;
5114
+ filter: grayscale(100%);
5115
+ opacity: .6;
5116
+ transition: width .5s cubic-bezier(.25,1,.5,1), height .5s cubic-bezier(.25,1,.5,1), filter .5s cubic-bezier(.25,1,.5,1), opacity .5s cubic-bezier(.25,1,.5,1);
5117
+ }
5118
+ .launcher:hover .launcher-glyph:is(img), :host([launcher-expanded]) .launcher-glyph:is(img) {
5119
+ filter: none;
5120
+ opacity: 1;
5121
+ }
5122
+ :host([data-launcher-style="bubble"]) .launcher-glyph:is(img) {
5123
+ width: 32px;
5124
+ height: 32px;
5125
+ filter: none;
5126
+ opacity: 1;
5127
+ }
4556
5128
  .launcher-status {
4557
5129
  position: absolute;
4558
- right: 1px;
4559
- bottom: 1px;
5130
+ right: -1px;
5131
+ bottom: -1px;
4560
5132
  width: 10px;
4561
5133
  height: 10px;
4562
5134
  border: 2px solid var(--ns-assistant-panel, var(--ns-assistant-default-panel));
@@ -4685,7 +5257,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4685
5257
  #conversationGeneration = 0;
4686
5258
  #messages;
4687
5259
  #thinking;
4688
- #media;
4689
5260
  #context;
4690
5261
  #modelContext;
4691
5262
  #pageContext;
@@ -4697,11 +5268,17 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4697
5268
  () => this.#primeSession(),
4698
5269
  () => this.focusComposer()
4699
5270
  );
5271
+ #publicConfiguration = new AssistantElementPublicConfigurationController(
5272
+ () => ({ embedId: this.embedId, serviceUrl: this.serviceUrl, fetch: this.#fetch }),
5273
+ (configuration) => this.#applyConfiguration(configuration),
5274
+ (loading) => this.#setPublicConfigurationLoading(loading)
5275
+ );
4700
5276
  #pendingUserEcho;
4701
5277
  #sessionState = "idle";
4702
5278
  #startOpenApplied = false;
4703
5279
  #readyDispatched = false;
4704
5280
  #turnInFlight = false;
5281
+ #fetch;
4705
5282
  #hostAppearance;
4706
5283
  #appearanceWarningKeys = /* @__PURE__ */ new Set();
4707
5284
  #appearanceStyleSnapshot = /* @__PURE__ */ new Map();
@@ -4711,6 +5288,17 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4711
5288
  embedId = "";
4712
5289
  /** Only for a dev or self-hosted service; the published snippet needs no origin. */
4713
5290
  serviceUrl = "";
5291
+ get fetch() {
5292
+ return this.#fetch;
5293
+ }
5294
+ set fetch(value) {
5295
+ if (this.#fetch === value) return;
5296
+ this.#fetch = value;
5297
+ if (this.#client) this.resetSession();
5298
+ if (!this.isConnected) return;
5299
+ if (this.embedId) this.#publicConfiguration.refresh();
5300
+ else this.#primeSession();
5301
+ }
4714
5302
  get appearance() {
4715
5303
  return this.#hostAppearance;
4716
5304
  }
@@ -4729,11 +5317,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4729
5317
  }
4730
5318
  return this.#appendMessage(role, text2);
4731
5319
  },
4732
- applyConfiguration: (configuration) => {
4733
- this.#appearance = resolveAppearance(configuration);
4734
- this.#syncAppearance();
4735
- this.#applyStartOpenPolicy();
4736
- },
5320
+ applyConfiguration: (configuration) => this.#applyConfiguration(configuration),
4737
5321
  labels: () => this.#appearance.labels,
4738
5322
  respond: (id, response) => this.respond(id, response),
4739
5323
  dispatchError: (detail) => this.#dispatchError(detail),
@@ -4749,7 +5333,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4749
5333
  client,
4750
5334
  sendMessage: (message) => this.sendMessage(message),
4751
5335
  updateModelContext: (update) => this.updateModelContext(update),
4752
- theme: this.#resolvedMode()
5336
+ theme: this.#environment.resolvedTheme()
4753
5337
  },
4754
5338
  {
4755
5339
  ...sandboxUrl === void 0 ? {} : { sandboxUrl },
@@ -4762,18 +5346,28 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4762
5346
  this.#revealLatest();
4763
5347
  }
4764
5348
  });
5349
+ #launcher = new AssistantElementLauncherController({
5350
+ host: this,
5351
+ appearance: () => this.#appearance,
5352
+ openPanel: () => this.open(),
5353
+ sendMessage: (message) => this.#sendGuarded(message)
5354
+ });
5355
+ #environment = new AssistantElementHostEnvironmentController({
5356
+ host: this,
5357
+ appearance: () => this.#appearance,
5358
+ applyTheme: () => this.#applyTheme(),
5359
+ close: () => this.#closeAndRestoreFocus()
5360
+ });
4765
5361
  connectedCallback() {
4766
5362
  if (!this.shadowRoot) this.attachShadow({ mode: "open" });
4767
5363
  if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute("session-endpoint") ?? "";
4768
5364
  if (!this.embedId) this.embedId = this.getAttribute("embed-id") ?? "";
4769
5365
  if (!this.serviceUrl) this.serviceUrl = this.getAttribute("service-url") ?? "";
4770
5366
  if (!this.sessionEndpoint && !this.embedId) this.#presentationGate.reveal();
4771
- this.#media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
4772
- this.#media?.addEventListener("change", this.#handleSystemTheme);
4773
- document.addEventListener("keydown", this.#handleDocumentKeydown);
4774
- document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
5367
+ this.#environment.connect();
4775
5368
  if (this.#appearance.behavior.startOpen) this.#applyStartOpenPolicy();
4776
5369
  this.#render();
5370
+ if (this.embedId) this.#publicConfiguration.connect();
4777
5371
  if (!this.#readyDispatched) {
4778
5372
  this.#readyDispatched = true;
4779
5373
  this.dispatchEvent(new CustomEvent("assistant-ready"));
@@ -4794,22 +5388,25 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4794
5388
  this.#clientEndpoint = "";
4795
5389
  this.#unsubscribeClient = void 0;
4796
5390
  this.#sessionBootstrap = void 0;
5391
+ this.#publicConfiguration.disconnect();
4797
5392
  this.#scroll.disconnect();
5393
+ this.#launcher.disconnect();
4798
5394
  this.#setBusy(false);
4799
- this.#media?.removeEventListener("change", this.#handleSystemTheme);
4800
- document.removeEventListener("keydown", this.#handleDocumentKeydown);
4801
- document.removeEventListener("pointerdown", this.#handleDocumentPointerDown);
5395
+ this.#environment.disconnect();
4802
5396
  }
4803
5397
  attributeChangedCallback(name) {
4804
5398
  if (name === "theme") this.#applyTheme();
4805
5399
  if (name === "open") this.#presentationGate.syncOpenState();
4806
5400
  }
4807
5401
  open() {
5402
+ this.#launcher.collapse(true);
4808
5403
  this.setAttribute("open", "");
5404
+ if (this.hasAttribute("data-presentation-ready")) queueMicrotask(() => this.focusComposer());
4809
5405
  this.dispatchEvent(new CustomEvent("assistant-open"));
4810
5406
  }
4811
5407
  close() {
4812
5408
  this.removeAttribute("open");
5409
+ this.#launcher.collapse(true);
4813
5410
  this.dispatchEvent(new CustomEvent("assistant-close"));
4814
5411
  }
4815
5412
  toggle() {
@@ -4946,17 +5543,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4946
5543
  if (generation === this.#conversationGeneration) this.#setBusy(false);
4947
5544
  }
4948
5545
  }
4949
- #handleSystemTheme = () => this.#applyTheme();
4950
- #handleDocumentKeydown = (event) => {
4951
- if (event.key === "Escape" && this.hasAttribute("open") && this.#appearance.behavior.closeOnEscape) {
4952
- this.#closeAndRestoreFocus();
4953
- }
4954
- };
4955
- #handleDocumentPointerDown = (event) => {
4956
- if (this.hasAttribute("open") && this.#appearance.behavior.closeOnOutsideClick && !event.composedPath().includes(this)) {
4957
- this.close();
4958
- }
4959
- };
4960
5546
  #ensureClient() {
4961
5547
  const key = sessionSourceKey(this);
4962
5548
  if (this.#client && this.#clientEndpoint === key) return this.#client;
@@ -4972,8 +5558,13 @@ var NoodleAssistantElement = class extends HTMLElementBase {
4972
5558
  const client = this.embedId ? createAssistantClient({
4973
5559
  embedId: this.embedId,
4974
5560
  ...this.serviceUrl ? { serviceUrl: this.serviceUrl } : {},
5561
+ ...this.#fetch ? { fetch: this.#fetch } : {},
4975
5562
  ...behavior
4976
- }) : createAssistantClient({ sessionEndpoint: this.sessionEndpoint, ...behavior });
5563
+ }) : createAssistantClient({
5564
+ sessionEndpoint: this.sessionEndpoint,
5565
+ ...this.#fetch ? { fetch: this.#fetch } : {},
5566
+ ...behavior
5567
+ });
4977
5568
  this.#client = client;
4978
5569
  this.#clientEndpoint = key;
4979
5570
  this.#unsubscribeClient = client.subscribe((event) => {
@@ -5002,6 +5593,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5002
5593
  this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
5003
5594
  this.#events.handle(event);
5004
5595
  if (event.event === "session_started") {
5596
+ this.#publicConfiguration.disconnect();
5597
+ this.removeAttribute("data-public-configuration-loading");
5005
5598
  this.#presentationGate.reveal();
5006
5599
  this.#setSessionState("ready");
5007
5600
  this.#messages?.querySelector(".conversation-error")?.remove();
@@ -5051,10 +5644,10 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5051
5644
  if (!this.#messages) return void 0;
5052
5645
  const message = document.createElement("div");
5053
5646
  message.className = `message ${role}`;
5054
- if (role === "assistant" && this.#appearance.behavior.showAvatars && this.#appearance.brand.avatar[this.#resolvedMode()]) {
5647
+ if (role === "assistant" && this.#appearance.behavior.showAvatars && this.#appearance.brand.avatar[this.#environment.resolvedTheme()]) {
5055
5648
  const avatar = document.createElement("img");
5056
5649
  avatar.className = "avatar";
5057
- avatar.src = this.#appearance.brand.avatar[this.#resolvedMode()] ?? "";
5650
+ avatar.src = this.#appearance.brand.avatar[this.#environment.resolvedTheme()] ?? "";
5058
5651
  avatar.alt = "";
5059
5652
  message.append(avatar);
5060
5653
  }
@@ -5135,12 +5728,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5135
5728
  this.#primeSession();
5136
5729
  this.dispatchEvent(new CustomEvent("assistant-new-conversation"));
5137
5730
  }
5138
- #resolvedMode() {
5139
- const configured = this.getAttribute("theme") ?? this.#appearance.theme.defaultMode;
5140
- return configured === "auto" ? this.#media?.matches ? "dark" : "light" : configured;
5141
- }
5142
5731
  #applyTheme() {
5143
- const mode = this.#resolvedMode();
5732
+ const mode = this.#environment.resolvedTheme();
5144
5733
  for (const warning of applyAssistantElementTheme({
5145
5734
  host: this,
5146
5735
  root: this.shadowRoot,
@@ -5163,13 +5752,23 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5163
5752
  updateAssistantAppTheme(app, mode);
5164
5753
  }
5165
5754
  }
5755
+ #applyConfiguration(configuration) {
5756
+ this.#appearance = resolveAppearance(configuration);
5757
+ this.#syncAppearance();
5758
+ this.#applyStartOpenPolicy();
5759
+ }
5760
+ #setPublicConfigurationLoading(loading) {
5761
+ this.toggleAttribute("data-public-configuration-loading", loading);
5762
+ if (loading) this.#presentationGate.syncOpenState();
5763
+ else this.#presentationGate.reveal();
5764
+ }
5166
5765
  #setSessionState(state) {
5167
5766
  this.#sessionState = state;
5168
5767
  syncAssistantSessionVisualState(this, this.shadowRoot, state, this.#appearance);
5169
5768
  }
5170
5769
  #closeAndRestoreFocus() {
5171
5770
  this.close();
5172
- this.shadowRoot?.querySelector(".launcher")?.focus();
5771
+ this.#launcher.focusTrigger();
5173
5772
  }
5174
5773
  #applyStartOpenPolicy() {
5175
5774
  if (this.#startOpenApplied) return;
@@ -5195,10 +5794,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5195
5794
  textarea.placeholder = appearance.labels.composerPlaceholder;
5196
5795
  textarea.setAttribute("aria-label", appearance.labels.composerPlaceholder);
5197
5796
  queryRequired(this.shadowRoot, ".send").textContent = appearance.labels.send;
5198
- queryRequired(this.shadowRoot, ".launcher").setAttribute(
5199
- "aria-label",
5200
- appearance.labels.open
5201
- );
5202
5797
  queryRequired(this.shadowRoot, ".close").setAttribute(
5203
5798
  "aria-label",
5204
5799
  appearance.labels.close
@@ -5212,11 +5807,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5212
5807
  button2.addEventListener("click", () => this.#sendGuarded(prompt));
5213
5808
  prompts.append(button2);
5214
5809
  }
5215
- queryRequired(this.shadowRoot, ".launcher").hidden = !appearance.behavior.showLauncher;
5216
5810
  queryRequired(this.shadowRoot, "header").hidden = !appearance.behavior.showHeader;
5217
5811
  const legal = queryRequired(this.shadowRoot, ".legal");
5218
5812
  legal.replaceChildren();
5219
5813
  appendLegalLinks(legal, this.#appearance);
5814
+ this.#launcher.sync();
5220
5815
  this.#applyTheme();
5221
5816
  }
5222
5817
  #render() {
@@ -5234,12 +5829,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5234
5829
  this.toggleAttribute("mobile-fullscreen", appearance.layout.mobileFullscreen);
5235
5830
  this.shadowRoot.innerHTML = assistantElementMarkup(
5236
5831
  appearance,
5237
- this.hasAttribute("open"),
5238
5832
  `${ASSISTANT_ELEMENT_STYLES}${presentationStyles}`
5239
5833
  );
5240
5834
  queryRequired(this.shadowRoot, "strong").textContent = appearance.brand.name;
5241
5835
  const logo = queryRequired(this.shadowRoot, ".brand-logo");
5242
- const logoUrl = appearance.brand.logo[this.#resolvedMode()];
5836
+ const logoUrl = appearance.brand.logo[this.#environment.resolvedTheme()];
5243
5837
  if (logoUrl) {
5244
5838
  logo.src = logoUrl;
5245
5839
  logo.alt = appearance.brand.name;
@@ -5267,12 +5861,9 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5267
5861
  this.#messages = this.shadowRoot.querySelector(".messages") ?? void 0;
5268
5862
  this.#messages?.append(...conversation);
5269
5863
  this.#thinking = this.#messages?.querySelector(".thinking") ?? void 0;
5270
- this.shadowRoot.querySelector(".launcher")?.addEventListener("click", () => {
5271
- this.open();
5272
- this.focusComposer();
5273
- });
5864
+ this.#launcher.connect(this.shadowRoot);
5274
5865
  this.shadowRoot.querySelector(".close")?.addEventListener("click", () => this.#closeAndRestoreFocus());
5275
- const form = queryRequired(this.shadowRoot, "form");
5866
+ const form = queryRequired(this.shadowRoot, ".composer");
5276
5867
  form.addEventListener("submit", (event) => {
5277
5868
  event.preventDefault();
5278
5869
  if (this.hasAttribute("busy")) {
@@ -5319,4 +5910,4 @@ export {
5319
5910
  dompurify/dist/purify.es.mjs:
5320
5911
  (*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE *)
5321
5912
  */
5322
- //# sourceMappingURL=chunk-FJYPE4GC.js.map
5913
+ //# sourceMappingURL=chunk-OZVDL77T.js.map