@webmaster-droid/web 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -197,7 +197,7 @@ function parseSelectedEditableFromTarget(target, pagePath) {
197
197
  }
198
198
  return selected;
199
199
  }
200
- function pickStringValue(document2, path, fallback, componentName, fallbackPropName) {
200
+ function pickStringValue(document2, path, fallback, componentName, fallbackPropName, missingBehavior = "throw") {
201
201
  const value = readByPath(document2, path);
202
202
  if (typeof value === "string" && value.trim()) {
203
203
  return value;
@@ -205,9 +205,12 @@ function pickStringValue(document2, path, fallback, componentName, fallbackPropN
205
205
  if (typeof fallback === "string") {
206
206
  return fallback;
207
207
  }
208
- throw new Error(
209
- `${componentName} missing content for "${path}". Provide a CMS value or set \`${fallbackPropName}\`.`
210
- );
208
+ const message = `${componentName} missing content for "${path}". Provide a CMS value or set \`${fallbackPropName}\`.`;
209
+ if (missingBehavior === "empty") {
210
+ console.error(message);
211
+ return "";
212
+ }
213
+ throw new Error(message);
211
214
  }
212
215
  function sanitizeRichTextHtml(html) {
213
216
  return sanitizeHtml(html, {
@@ -229,7 +232,7 @@ function EditableText({
229
232
  ...rest
230
233
  }) {
231
234
  const { document: document2, enabled } = useEditableDocument();
232
- const value = pickStringValue(document2, path, fallback, "EditableText", "fallback");
235
+ const value = pickStringValue(document2, path, fallback, "EditableText", "fallback", "empty");
233
236
  const attrs = enabled ? editableMeta({
234
237
  path,
235
238
  label: label ?? path,
@@ -247,7 +250,14 @@ function EditableRichText({
247
250
  ...rest
248
251
  }) {
249
252
  const { document: document2, enabled } = useEditableDocument();
250
- const value = pickStringValue(document2, path, fallback, "EditableRichText", "fallback");
253
+ const value = pickStringValue(
254
+ document2,
255
+ path,
256
+ fallback,
257
+ "EditableRichText",
258
+ "fallback",
259
+ "empty"
260
+ );
251
261
  const sanitizedHtml = sanitizeRichTextHtml(value);
252
262
  const attrs = enabled ? editableMeta({
253
263
  path,
@@ -270,8 +280,22 @@ function EditableImage({
270
280
  ...rest
271
281
  }) {
272
282
  const { document: document2, enabled } = useEditableDocument();
273
- const src = pickStringValue(document2, path, fallbackSrc, "EditableImage", "fallbackSrc");
274
- const alt = altPath ? pickStringValue(document2, altPath, fallbackAlt, "EditableImage", "fallbackAlt") : fallbackAlt ?? "";
283
+ const src = pickStringValue(
284
+ document2,
285
+ path,
286
+ fallbackSrc,
287
+ "EditableImage",
288
+ "fallbackSrc",
289
+ "empty"
290
+ );
291
+ const alt = altPath ? pickStringValue(
292
+ document2,
293
+ altPath,
294
+ fallbackAlt,
295
+ "EditableImage",
296
+ "fallbackAlt",
297
+ "empty"
298
+ ) : fallbackAlt ?? "";
275
299
  const attrs = enabled ? editableMeta({
276
300
  path,
277
301
  label: label ?? path,
@@ -290,13 +314,21 @@ function EditableLink({
290
314
  ...rest
291
315
  }) {
292
316
  const { document: document2, enabled } = useEditableDocument();
293
- const href = pickStringValue(document2, hrefPath, fallbackHref, "EditableLink", "fallbackHref");
317
+ const href = pickStringValue(
318
+ document2,
319
+ hrefPath,
320
+ fallbackHref,
321
+ "EditableLink",
322
+ "fallbackHref",
323
+ "empty"
324
+ );
294
325
  const text = pickStringValue(
295
326
  document2,
296
327
  labelPath,
297
328
  fallbackLabel,
298
329
  "EditableLink",
299
- "fallbackLabel"
330
+ "fallbackLabel",
331
+ "empty"
300
332
  );
301
333
  const attrs = enabled ? editableMeta({
302
334
  path: labelPath,
@@ -610,6 +642,13 @@ function getSupabaseBrowserClient(config) {
610
642
  // src/context.tsx
611
643
  import { jsx as jsx2 } from "react/jsx-runtime";
612
644
  var WebmasterDroidContext = createContext2(null);
645
+ var DEFAULT_MODEL_CAPABILITIES = {
646
+ contentEdit: true,
647
+ themeTokenEdit: true,
648
+ imageGenerate: false,
649
+ imageEdit: false,
650
+ visionAssist: false
651
+ };
613
652
  function WebmasterDroidProvider(props) {
614
653
  const resolvedConfig = useMemo(
615
654
  () => resolveWebmasterDroidConfig(props.config),
@@ -641,6 +680,9 @@ function WebmasterDroidProvider(props) {
641
680
  const [modelId, setModelId] = useState(null);
642
681
  const [showModelPickerState, setShowModelPickerState] = useState(false);
643
682
  const [modelOptions, setModelOptions] = useState([]);
683
+ const [capabilities, setCapabilities] = useState(
684
+ DEFAULT_MODEL_CAPABILITIES
685
+ );
644
686
  const [includeThinking, setIncludeThinking] = useState(false);
645
687
  const [refreshKey, setRefreshKey] = useState(0);
646
688
  const [selectedElement, setSelectedElement] = useState(null);
@@ -675,6 +717,7 @@ function WebmasterDroidProvider(props) {
675
717
  const preferredDefault = options.some((option) => option.id === models.defaultModelId) ? models.defaultModelId : options[0]?.id ?? models.defaultModelId;
676
718
  setShowModelPickerState(models.showModelPicker);
677
719
  setModelOptions(options);
720
+ setCapabilities(models.capabilities ?? DEFAULT_MODEL_CAPABILITIES);
678
721
  setModelId((current) => {
679
722
  if (current && options.some((option) => option.id === current)) {
680
723
  return current;
@@ -685,6 +728,7 @@ function WebmasterDroidProvider(props) {
685
728
  if (!ignore) {
686
729
  setShowModelPickerState(false);
687
730
  setModelOptions([]);
731
+ setCapabilities(DEFAULT_MODEL_CAPABILITIES);
688
732
  setModelId((current) => current ?? resolvedConfig.defaultModelId);
689
733
  }
690
734
  });
@@ -705,6 +749,7 @@ function WebmasterDroidProvider(props) {
705
749
  setModelId,
706
750
  showModelPicker,
707
751
  modelOptions,
752
+ capabilities,
708
753
  includeThinking,
709
754
  setIncludeThinking,
710
755
  refreshKey,
@@ -721,6 +766,7 @@ function WebmasterDroidProvider(props) {
721
766
  modelId,
722
767
  showModelPicker,
723
768
  modelOptions,
769
+ capabilities,
724
770
  includeThinking,
725
771
  refreshKey,
726
772
  authConfigured,
@@ -737,6 +783,9 @@ function useWebmasterDroid() {
737
783
  return context;
738
784
  }
739
785
 
786
+ // src/overlay.tsx
787
+ import { useEffect as useEffect3 } from "react";
788
+
740
789
  // src/overlay/utils.ts
741
790
  function createMessage(role, text, status) {
742
791
  return {
@@ -831,6 +880,84 @@ var OVERLAY_FONT_FAMILY = "var(--font-ibm-plex-mono), ui-monospace, SFMono-Regul
831
880
  // src/overlay/components.tsx
832
881
  import ReactMarkdown from "react-markdown";
833
882
  import remarkGfm from "remark-gfm";
883
+
884
+ // src/overlay/class-names.ts
885
+ var OVERLAY_CLASS_NAMES = {
886
+ panel: "wmd-panel",
887
+ launcherButton: "wmd-launcher",
888
+ header: "wmd-header",
889
+ headerRow: "wmd-header-row",
890
+ publishState: "wmd-publish-state",
891
+ publishStatePublished: "wmd-publish-state--published",
892
+ publishStateUnpublished: "wmd-publish-state--unpublished",
893
+ publishButton: "wmd-publish-button",
894
+ tabs: "wmd-tabs",
895
+ tabButton: "wmd-tab-button",
896
+ tabButtonActive: "wmd-tab-button--active",
897
+ loginTitle: "wmd-login-title",
898
+ headerActions: "wmd-header-actions",
899
+ iconButton: "wmd-icon-button",
900
+ icon: "wmd-icon",
901
+ closeButton: "wmd-close-button",
902
+ loginSection: "wmd-login-section",
903
+ loginWarning: "wmd-login-warning",
904
+ loginCard: "wmd-login-card",
905
+ loginHeading: "wmd-login-heading",
906
+ loginFields: "wmd-login-fields",
907
+ fieldInput: "wmd-field-input",
908
+ primaryButton: "wmd-primary-button",
909
+ chatSection: "wmd-chat-section",
910
+ message: "wmd-message",
911
+ messageTool: "wmd-message--tool",
912
+ messageUser: "wmd-message--user",
913
+ messageThinking: "wmd-message--thinking",
914
+ messageAssistant: "wmd-message--assistant",
915
+ messageFallback: "wmd-message--fallback",
916
+ assistantAvatar: "wmd-assistant-avatar",
917
+ assistantAvatarFallback: "wmd-assistant-avatar-fallback",
918
+ assistantAvatarPending: "wmd-assistant-avatar--pending",
919
+ markdownContent: "wmd-markdown-content",
920
+ pendingShim: "wmd-pending-shim",
921
+ footer: "wmd-footer",
922
+ modelRow: "wmd-model-row",
923
+ modelLabel: "wmd-model-label",
924
+ modelSelect: "wmd-model-select",
925
+ selectedElement: "wmd-selected-element",
926
+ selectedKind: "wmd-selected-kind",
927
+ selectedText: "wmd-selected-text",
928
+ selectedLabel: "wmd-selected-label",
929
+ selectedClearButton: "wmd-selected-clear",
930
+ selectedClearIcon: "wmd-selected-clear-icon",
931
+ composerRow: "wmd-composer-row",
932
+ composerInput: "wmd-composer-input",
933
+ sendButton: "wmd-send-button",
934
+ historySection: "wmd-history-section",
935
+ historyColumns: "wmd-history-columns",
936
+ historyCard: "wmd-history-card",
937
+ historyCardTitle: "wmd-history-card-title",
938
+ historyList: "wmd-history-list",
939
+ historyStack: "wmd-history-stack",
940
+ historyItem: "wmd-history-item",
941
+ historyItemCheckpoint: "wmd-history-item--checkpoint",
942
+ historyTextBlock: "wmd-history-text",
943
+ historyTimestamp: "wmd-history-timestamp",
944
+ historyReason: "wmd-history-reason",
945
+ historyActions: "wmd-history-actions",
946
+ historyAction: "wmd-history-action",
947
+ historyDelete: "wmd-history-delete",
948
+ emptyText: "wmd-empty-text"
949
+ };
950
+ function overlayClass(slot, className) {
951
+ if (!className) {
952
+ return OVERLAY_CLASS_NAMES[slot];
953
+ }
954
+ return `${OVERLAY_CLASS_NAMES[slot]} ${className}`;
955
+ }
956
+ function joinClassNames(...parts) {
957
+ return parts.filter(Boolean).join(" ");
958
+ }
959
+
960
+ // src/overlay/components.tsx
834
961
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
835
962
  function OverlayHeader({
836
963
  isAuthenticated,
@@ -843,12 +970,15 @@ function OverlayHeader({
843
970
  onClearChat,
844
971
  onClose
845
972
  }) {
846
- return /* @__PURE__ */ jsx3("header", { className: "border-b border-stone-300 bg-[#f3eee5] p-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
973
+ return /* @__PURE__ */ jsx3("header", { className: overlayClass("header", "border-b border-stone-300 bg-[#f3eee5] p-2"), children: /* @__PURE__ */ jsxs("div", { className: overlayClass("headerRow", "flex items-center gap-2"), children: [
847
974
  isAuthenticated ? /* @__PURE__ */ jsxs(Fragment, { children: [
848
975
  /* @__PURE__ */ jsx3(
849
976
  "span",
850
977
  {
851
- className: `rounded border px-1.5 py-0.5 text-[10px] font-medium leading-4 ${publishState === "Published" ? "border-stone-300 bg-[#ece5d9] text-stone-600" : "border-stone-500 bg-[#ded4c3] text-stone-800"}`,
978
+ className: joinClassNames(
979
+ overlayClass("publishState", "rounded border px-1.5 py-0.5 text-[10px] font-medium leading-4"),
980
+ publishState === "Published" ? overlayClass("publishStatePublished", "border-stone-300 bg-[#ece5d9] text-stone-600") : overlayClass("publishStateUnpublished", "border-stone-500 bg-[#ded4c3] text-stone-800")
981
+ ),
852
982
  children: publishState
853
983
  }
854
984
  ),
@@ -856,18 +986,24 @@ function OverlayHeader({
856
986
  "button",
857
987
  {
858
988
  type: "button",
859
- className: "rounded border border-stone-700 bg-stone-800 px-2 py-1 text-[11px] font-semibold leading-4 text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50",
989
+ className: overlayClass(
990
+ "publishButton",
991
+ "rounded border border-stone-700 bg-stone-800 px-2 py-1 text-[11px] font-semibold leading-4 text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50"
992
+ ),
860
993
  onClick: onPublish,
861
994
  disabled: !isAuthenticated,
862
995
  children: "Publish"
863
996
  }
864
997
  ),
865
- /* @__PURE__ */ jsxs("div", { className: "inline-flex rounded-md border border-stone-300 bg-[#e8dfd1] p-0.5", children: [
998
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("tabs", "inline-flex rounded-md border border-stone-300 bg-[#e8dfd1] p-0.5"), children: [
866
999
  /* @__PURE__ */ jsx3(
867
1000
  "button",
868
1001
  {
869
1002
  type: "button",
870
- className: `rounded px-2 py-1 text-[11px] font-medium leading-4 ${activeTab === "chat" ? "bg-[#f7f2e8] text-stone-900 shadow-sm" : "text-stone-600 hover:text-stone-900"}`,
1003
+ className: joinClassNames(
1004
+ overlayClass("tabButton", "rounded px-2 py-1 text-[11px] font-medium leading-4"),
1005
+ activeTab === "chat" ? overlayClass("tabButtonActive", "bg-[#f7f2e8] text-stone-900 shadow-sm") : "text-stone-600 hover:text-stone-900"
1006
+ ),
871
1007
  onClick: () => onTabChange("chat"),
872
1008
  children: "Chat"
873
1009
  }
@@ -876,7 +1012,10 @@ function OverlayHeader({
876
1012
  "button",
877
1013
  {
878
1014
  type: "button",
879
- className: `rounded px-2 py-1 text-[11px] font-medium leading-4 ${activeTab === "history" ? "bg-[#f7f2e8] text-stone-900 shadow-sm" : "text-stone-600 hover:text-stone-900"}`,
1015
+ className: joinClassNames(
1016
+ overlayClass("tabButton", "rounded px-2 py-1 text-[11px] font-medium leading-4"),
1017
+ activeTab === "history" ? overlayClass("tabButtonActive", "bg-[#f7f2e8] text-stone-900 shadow-sm") : "text-stone-600 hover:text-stone-900"
1018
+ ),
880
1019
  onClick: () => onTabChange("history"),
881
1020
  children: [
882
1021
  "History (",
@@ -886,8 +1025,8 @@ function OverlayHeader({
886
1025
  }
887
1026
  )
888
1027
  ] })
889
- ] }) : /* @__PURE__ */ jsx3("h2", { className: "text-[12px] font-semibold text-stone-700", children: "Login" }),
890
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
1028
+ ] }) : /* @__PURE__ */ jsx3("h2", { className: overlayClass("loginTitle", "text-[12px] font-semibold text-stone-700"), children: "Login" }),
1029
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("headerActions", "ml-auto flex items-center gap-1"), children: [
891
1030
  isAuthenticated ? /* @__PURE__ */ jsx3(
892
1031
  "button",
893
1032
  {
@@ -895,25 +1034,40 @@ function OverlayHeader({
895
1034
  "aria-label": "Clear chat",
896
1035
  title: "Clear chat",
897
1036
  disabled: clearChatDisabled,
898
- className: "inline-flex h-6 w-6 items-center justify-center rounded border border-stone-300 text-stone-600 hover:bg-[#efe8dc] hover:text-stone-800 disabled:cursor-not-allowed disabled:opacity-50",
1037
+ className: overlayClass(
1038
+ "iconButton",
1039
+ "inline-flex h-6 w-6 items-center justify-center rounded border border-stone-300 text-stone-600 hover:bg-[#efe8dc] hover:text-stone-800 disabled:cursor-not-allowed disabled:opacity-50"
1040
+ ),
899
1041
  onClick: onClearChat,
900
- children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 20 20", fill: "none", className: "h-3.5 w-3.5", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
901
- "path",
1042
+ children: /* @__PURE__ */ jsx3(
1043
+ "svg",
902
1044
  {
903
- d: "M4.5 5.5H15.5M8 3.75H12M7 7.5V13.5M10 7.5V13.5M13 7.5V13.5M6.5 5.5L7 15C7.03 15.6 7.53 16.08 8.13 16.08H11.87C12.47 16.08 12.97 15.6 13 15L13.5 5.5",
904
- stroke: "currentColor",
905
- strokeWidth: "1.4",
906
- strokeLinecap: "round",
907
- strokeLinejoin: "round"
1045
+ viewBox: "0 0 20 20",
1046
+ fill: "none",
1047
+ className: overlayClass("icon", "h-3.5 w-3.5"),
1048
+ "aria-hidden": "true",
1049
+ children: /* @__PURE__ */ jsx3(
1050
+ "path",
1051
+ {
1052
+ d: "M4.5 5.5H15.5M8 3.75H12M7 7.5V13.5M10 7.5V13.5M13 7.5V13.5M6.5 5.5L7 15C7.03 15.6 7.53 16.08 8.13 16.08H11.87C12.47 16.08 12.97 15.6 13 15L13.5 5.5",
1053
+ stroke: "currentColor",
1054
+ strokeWidth: "1.4",
1055
+ strokeLinecap: "round",
1056
+ strokeLinejoin: "round"
1057
+ }
1058
+ )
908
1059
  }
909
- ) })
1060
+ )
910
1061
  }
911
1062
  ) : null,
912
1063
  /* @__PURE__ */ jsx3(
913
1064
  "button",
914
1065
  {
915
1066
  type: "button",
916
- className: "rounded border border-stone-300 px-2 py-1 text-[11px] leading-4 text-stone-700 hover:bg-[#efe8dc]",
1067
+ className: overlayClass(
1068
+ "closeButton",
1069
+ "rounded border border-stone-300 px-2 py-1 text-[11px] leading-4 text-stone-700 hover:bg-[#efe8dc]"
1070
+ ),
917
1071
  onClick: onClose,
918
1072
  children: "Close"
919
1073
  }
@@ -930,41 +1084,68 @@ function OverlayLoginPanel({
930
1084
  onPasswordChange,
931
1085
  onSignIn
932
1086
  }) {
933
- return /* @__PURE__ */ jsx3("section", { className: "flex min-h-0 flex-1 items-center justify-center bg-[#ece7dd] p-3", children: !authConfigured ? /* @__PURE__ */ jsx3("div", { className: "w-full max-w-sm rounded border border-red-300 bg-[#f8f3e9] p-3 text-[11px] leading-4 text-red-700", children: "Missing Supabase config (`supabaseUrl` / `supabaseAnonKey`)." }) : /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm rounded border border-stone-300 bg-[#f8f3e9] p-3", children: [
934
- /* @__PURE__ */ jsx3("h3", { className: "mb-2 text-[12px] font-semibold text-stone-700", children: "Sign in" }),
935
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
936
- /* @__PURE__ */ jsx3(
937
- "input",
938
- {
939
- type: "text",
940
- value: email,
941
- onChange: (event) => onEmailChange(event.target.value),
942
- placeholder: "login",
943
- className: "w-full rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] text-stone-900 outline-none focus:border-stone-500"
944
- }
945
- ),
946
- /* @__PURE__ */ jsx3(
947
- "input",
948
- {
949
- type: "password",
950
- value: password,
951
- onChange: (event) => onPasswordChange(event.target.value),
952
- placeholder: "Password",
953
- className: "w-full rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] text-stone-900 outline-none focus:border-stone-500"
954
- }
1087
+ return /* @__PURE__ */ jsx3(
1088
+ "section",
1089
+ {
1090
+ className: overlayClass(
1091
+ "loginSection",
1092
+ "flex min-h-0 flex-1 items-center justify-center bg-[#ece7dd] p-3"
955
1093
  ),
956
- /* @__PURE__ */ jsx3(
957
- "button",
1094
+ children: !authConfigured ? /* @__PURE__ */ jsx3(
1095
+ "div",
958
1096
  {
959
- type: "button",
960
- onClick: onSignIn,
961
- disabled: signingIn || !email.trim() || !password,
962
- className: "w-full rounded border border-stone-700 bg-stone-800 px-2 py-1.5 text-[12px] font-medium text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50",
963
- children: signingIn ? "Signing in" : "Sign in"
1097
+ className: overlayClass(
1098
+ "loginWarning",
1099
+ "w-full max-w-sm rounded border border-red-300 bg-[#f8f3e9] p-3 text-[11px] leading-4 text-red-700"
1100
+ ),
1101
+ children: "Missing Supabase config (`supabaseUrl` / `supabaseAnonKey`)."
964
1102
  }
965
- )
966
- ] })
967
- ] }) });
1103
+ ) : /* @__PURE__ */ jsxs("div", { className: overlayClass("loginCard", "w-full max-w-sm rounded border border-stone-300 bg-[#f8f3e9] p-3"), children: [
1104
+ /* @__PURE__ */ jsx3("h3", { className: overlayClass("loginHeading", "mb-2 text-[12px] font-semibold text-stone-700"), children: "Sign in" }),
1105
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("loginFields", "space-y-2"), children: [
1106
+ /* @__PURE__ */ jsx3(
1107
+ "input",
1108
+ {
1109
+ type: "text",
1110
+ value: email,
1111
+ onChange: (event) => onEmailChange(event.target.value),
1112
+ placeholder: "login",
1113
+ className: overlayClass(
1114
+ "fieldInput",
1115
+ "w-full rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] text-stone-900 outline-none focus:border-stone-500"
1116
+ )
1117
+ }
1118
+ ),
1119
+ /* @__PURE__ */ jsx3(
1120
+ "input",
1121
+ {
1122
+ type: "password",
1123
+ value: password,
1124
+ onChange: (event) => onPasswordChange(event.target.value),
1125
+ placeholder: "Password",
1126
+ className: overlayClass(
1127
+ "fieldInput",
1128
+ "w-full rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] text-stone-900 outline-none focus:border-stone-500"
1129
+ )
1130
+ }
1131
+ ),
1132
+ /* @__PURE__ */ jsx3(
1133
+ "button",
1134
+ {
1135
+ type: "button",
1136
+ onClick: onSignIn,
1137
+ disabled: signingIn || !email.trim() || !password,
1138
+ className: overlayClass(
1139
+ "primaryButton",
1140
+ "w-full rounded border border-stone-700 bg-stone-800 px-2 py-1.5 text-[12px] font-medium text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50"
1141
+ ),
1142
+ children: signingIn ? "Signing in" : "Sign in"
1143
+ }
1144
+ )
1145
+ ] })
1146
+ ] })
1147
+ }
1148
+ );
968
1149
  }
969
1150
  function OverlayChatPanel({
970
1151
  messages,
@@ -987,14 +1168,29 @@ function OverlayChatPanel({
987
1168
  isAuthenticated
988
1169
  }) {
989
1170
  return /* @__PURE__ */ jsxs(Fragment, { children: [
990
- /* @__PURE__ */ jsxs("section", { className: "flex-1 space-y-1 overflow-auto bg-[#ece7dd] p-2", children: [
1171
+ /* @__PURE__ */ jsxs("section", { className: overlayClass("chatSection", "flex-1 space-y-1 overflow-auto bg-[#ece7dd] p-2"), children: [
991
1172
  messages.map((entry) => {
992
1173
  const isAssistant = entry.role === "assistant";
993
1174
  const isPendingAssistant = isAssistant && entry.status === "pending";
994
1175
  return /* @__PURE__ */ jsx3(
995
1176
  "div",
996
1177
  {
997
- className: entry.role === "tool" ? "max-w-[96%] px-0.5 py-0 text-[10px] leading-tight text-stone-500" : `max-w-[92%] rounded-md py-1.5 text-[12px] leading-4 ${entry.role === "user" ? "ml-auto bg-[#2e2b27] px-2 text-stone-50" : entry.role === "thinking" ? "bg-[#e3dbce] px-2 text-stone-700" : isAssistant ? "relative border border-[#d6ccbb] bg-[#f8f3e9] pl-8 pr-2 text-stone-800" : "bg-[#ddd2bf] px-2 text-stone-800"}`,
1178
+ className: joinClassNames(
1179
+ overlayClass("message"),
1180
+ entry.role === "tool" ? overlayClass("messageTool", "max-w-[96%] px-0.5 py-0 text-[10px] leading-tight text-stone-500") : entry.role === "user" ? overlayClass(
1181
+ "messageUser",
1182
+ "ml-auto max-w-[92%] rounded-md bg-[#2e2b27] px-2 py-1.5 text-[12px] leading-4 text-stone-50"
1183
+ ) : entry.role === "thinking" ? overlayClass(
1184
+ "messageThinking",
1185
+ "max-w-[92%] rounded-md bg-[#e3dbce] px-2 py-1.5 text-[12px] leading-4 text-stone-700"
1186
+ ) : isAssistant ? overlayClass(
1187
+ "messageAssistant",
1188
+ "relative max-w-[92%] rounded-md border border-[#d6ccbb] bg-[#f8f3e9] pl-8 pr-2 py-1.5 text-[12px] leading-4 text-stone-800"
1189
+ ) : overlayClass(
1190
+ "messageFallback",
1191
+ "max-w-[92%] rounded-md bg-[#ddd2bf] px-2 py-1.5 text-[12px] leading-4 text-stone-800"
1192
+ )
1193
+ ),
998
1194
  children: entry.role === "tool" ? /* @__PURE__ */ jsx3("span", { children: entry.text }) : /* @__PURE__ */ jsxs(Fragment, { children: [
999
1195
  isAssistant ? showAssistantAvatarImage ? /* @__PURE__ */ jsx3(
1000
1196
  "img",
@@ -1002,18 +1198,39 @@ function OverlayChatPanel({
1002
1198
  src: assistantAvatarUrl,
1003
1199
  alt: "",
1004
1200
  "aria-hidden": "true",
1005
- className: `pointer-events-none absolute left-2 top-1.5 h-[18px] w-[18px] select-none rounded-full border border-[#d6ccbb] bg-[#efe8dc] object-cover ${isPendingAssistant ? "animate-pulse" : ""}`,
1201
+ className: joinClassNames(
1202
+ overlayClass(
1203
+ "assistantAvatar",
1204
+ "pointer-events-none absolute left-2 top-1.5 h-[18px] w-[18px] select-none rounded-full border border-[#d6ccbb] bg-[#efe8dc] object-cover"
1205
+ ),
1206
+ isPendingAssistant ? overlayClass("assistantAvatarPending", "animate-pulse") : null
1207
+ ),
1006
1208
  onError: onAssistantAvatarError
1007
1209
  }
1008
1210
  ) : /* @__PURE__ */ jsx3(
1009
1211
  "span",
1010
1212
  {
1011
1213
  "aria-hidden": "true",
1012
- className: `pointer-events-none absolute left-2 top-1.5 inline-flex h-[18px] w-[18px] select-none items-center justify-center rounded-full border border-[#d6ccbb] bg-[#efe8dc] text-[9px] font-semibold text-stone-700 ${isPendingAssistant ? "animate-pulse" : ""}`,
1214
+ className: joinClassNames(
1215
+ overlayClass(
1216
+ "assistantAvatarFallback",
1217
+ "pointer-events-none absolute left-2 top-1.5 inline-flex h-[18px] w-[18px] select-none items-center justify-center rounded-full border border-[#d6ccbb] bg-[#efe8dc] text-[9px] font-semibold text-stone-700"
1218
+ ),
1219
+ isPendingAssistant ? overlayClass("assistantAvatarPending", "animate-pulse") : null
1220
+ ),
1013
1221
  children: assistantAvatarFallbackLabel
1014
1222
  }
1015
1223
  ) : null,
1016
- /* @__PURE__ */ jsx3("div", { className: "max-w-none text-inherit [&_code]:rounded [&_code]:bg-stone-900/10 [&_code]:px-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_p]:mb-1 [&_p:last-child]:mb-0 [&_ul]:list-disc [&_ul]:pl-4", children: isPendingAssistant && !entry.text.trim() ? /* @__PURE__ */ jsx3("span", { className: "block h-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx3(ReactMarkdown, { remarkPlugins: [remarkGfm], children: entry.text }) })
1224
+ /* @__PURE__ */ jsx3(
1225
+ "div",
1226
+ {
1227
+ className: overlayClass(
1228
+ "markdownContent",
1229
+ "max-w-none text-inherit [&_code]:rounded [&_code]:bg-stone-900/10 [&_code]:px-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_p]:mb-1 [&_p:last-child]:mb-0 [&_ul]:list-disc [&_ul]:pl-4"
1230
+ ),
1231
+ children: isPendingAssistant && !entry.text.trim() ? /* @__PURE__ */ jsx3("span", { className: overlayClass("pendingShim", "block h-4"), "aria-hidden": "true" }) : /* @__PURE__ */ jsx3(ReactMarkdown, { remarkPlugins: [remarkGfm], children: entry.text })
1232
+ }
1233
+ )
1017
1234
  ] })
1018
1235
  },
1019
1236
  entry.id
@@ -1021,13 +1238,13 @@ function OverlayChatPanel({
1021
1238
  }),
1022
1239
  /* @__PURE__ */ jsx3("div", { ref: chatEndRef })
1023
1240
  ] }),
1024
- /* @__PURE__ */ jsxs("footer", { className: "border-t border-stone-300 bg-[#f3eee5] p-2", children: [
1025
- showModelPicker && selectableModels.length > 1 ? /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center gap-1.5", children: [
1241
+ /* @__PURE__ */ jsxs("footer", { className: overlayClass("footer", "border-t border-stone-300 bg-[#f3eee5] p-2"), children: [
1242
+ showModelPicker && selectableModels.length > 1 ? /* @__PURE__ */ jsxs("div", { className: overlayClass("modelRow", "mb-1 flex items-center gap-1.5"), children: [
1026
1243
  /* @__PURE__ */ jsx3(
1027
1244
  "label",
1028
1245
  {
1029
1246
  htmlFor: "admin-model-picker",
1030
- className: "text-[10px] font-semibold uppercase tracking-wide text-stone-600",
1247
+ className: overlayClass("modelLabel", "text-[10px] font-semibold uppercase tracking-wide text-stone-600"),
1031
1248
  children: "Model"
1032
1249
  }
1033
1250
  ),
@@ -1038,45 +1255,78 @@ function OverlayChatPanel({
1038
1255
  value: modelId ?? selectableModels[0]?.id,
1039
1256
  onChange: (event) => onModelChange(event.target.value),
1040
1257
  disabled: sending,
1041
- className: "h-7 min-w-0 flex-1 rounded border border-stone-300 bg-[#f7f2e8] px-2 text-[11px] text-stone-800 outline-none focus:border-stone-500 disabled:cursor-not-allowed disabled:opacity-60",
1258
+ className: overlayClass(
1259
+ "modelSelect",
1260
+ "h-7 min-w-0 flex-1 rounded border border-stone-300 bg-[#f7f2e8] px-2 text-[11px] text-stone-800 outline-none focus:border-stone-500 disabled:cursor-not-allowed disabled:opacity-60"
1261
+ ),
1042
1262
  children: selectableModels.map((option) => /* @__PURE__ */ jsx3("option", { value: option.id, children: option.label }, option.id))
1043
1263
  }
1044
1264
  )
1045
1265
  ] }) : null,
1046
- selectedElement ? /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center gap-1 rounded border border-stone-300 bg-[#e8dfd1] px-1.5 py-1", children: [
1047
- /* @__PURE__ */ jsx3("span", { className: "inline-flex shrink-0 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] px-1 py-0.5 text-[9px] font-semibold text-stone-700", children: kindIcon(selectedElement.kind) }),
1048
- /* @__PURE__ */ jsxs("p", { className: "min-w-0 flex-1 truncate text-[10px] leading-3.5 text-stone-600", children: [
1049
- /* @__PURE__ */ jsx3("span", { className: "font-semibold text-stone-800", children: selectedElement.label }),
1050
- /* @__PURE__ */ jsxs("span", { children: [
1051
- " \xB7 ",
1052
- selectedElement.path
1053
- ] }),
1054
- selectedElement.preview ? /* @__PURE__ */ jsxs("span", { children: [
1055
- " \xB7 ",
1056
- selectedElement.preview
1057
- ] }) : null
1058
- ] }),
1059
- /* @__PURE__ */ jsx3(
1060
- "button",
1061
- {
1062
- type: "button",
1063
- "aria-label": "Clear selected element",
1064
- title: "Clear selected element",
1065
- className: "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] text-stone-700 hover:bg-[#efe8dc]",
1066
- onClick: onClearSelectedElement,
1067
- children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 20 20", fill: "none", className: "h-3 w-3", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
1068
- "path",
1266
+ selectedElement ? /* @__PURE__ */ jsxs(
1267
+ "div",
1268
+ {
1269
+ className: overlayClass(
1270
+ "selectedElement",
1271
+ "mb-1 flex items-center gap-1 rounded border border-stone-300 bg-[#e8dfd1] px-1.5 py-1"
1272
+ ),
1273
+ children: [
1274
+ /* @__PURE__ */ jsx3(
1275
+ "span",
1069
1276
  {
1070
- d: "M5 5L15 15M15 5L5 15",
1071
- stroke: "currentColor",
1072
- strokeWidth: "1.5",
1073
- strokeLinecap: "round"
1277
+ className: overlayClass(
1278
+ "selectedKind",
1279
+ "inline-flex shrink-0 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] px-1 py-0.5 text-[9px] font-semibold text-stone-700"
1280
+ ),
1281
+ children: kindIcon(selectedElement.kind)
1074
1282
  }
1075
- ) })
1076
- }
1077
- )
1078
- ] }) : null,
1079
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
1283
+ ),
1284
+ /* @__PURE__ */ jsxs("p", { className: overlayClass("selectedText", "min-w-0 flex-1 truncate text-[10px] leading-3.5 text-stone-600"), children: [
1285
+ /* @__PURE__ */ jsx3("span", { className: overlayClass("selectedLabel", "font-semibold text-stone-800"), children: selectedElement.label }),
1286
+ /* @__PURE__ */ jsxs("span", { children: [
1287
+ " \xB7 ",
1288
+ selectedElement.path
1289
+ ] }),
1290
+ selectedElement.preview ? /* @__PURE__ */ jsxs("span", { children: [
1291
+ " \xB7 ",
1292
+ selectedElement.preview
1293
+ ] }) : null
1294
+ ] }),
1295
+ /* @__PURE__ */ jsx3(
1296
+ "button",
1297
+ {
1298
+ type: "button",
1299
+ "aria-label": "Clear selected element",
1300
+ title: "Clear selected element",
1301
+ className: overlayClass(
1302
+ "selectedClearButton",
1303
+ "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] text-stone-700 hover:bg-[#efe8dc]"
1304
+ ),
1305
+ onClick: onClearSelectedElement,
1306
+ children: /* @__PURE__ */ jsx3(
1307
+ "svg",
1308
+ {
1309
+ viewBox: "0 0 20 20",
1310
+ fill: "none",
1311
+ className: overlayClass("selectedClearIcon", "h-3 w-3"),
1312
+ "aria-hidden": "true",
1313
+ children: /* @__PURE__ */ jsx3(
1314
+ "path",
1315
+ {
1316
+ d: "M5 5L15 15M15 5L5 15",
1317
+ stroke: "currentColor",
1318
+ strokeWidth: "1.5",
1319
+ strokeLinecap: "round"
1320
+ }
1321
+ )
1322
+ }
1323
+ )
1324
+ }
1325
+ )
1326
+ ]
1327
+ }
1328
+ ) : null,
1329
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("composerRow", "flex gap-1.5"), children: [
1080
1330
  /* @__PURE__ */ jsx3(
1081
1331
  "textarea",
1082
1332
  {
@@ -1085,7 +1335,10 @@ function OverlayChatPanel({
1085
1335
  onKeyDown: onMessageKeyDown,
1086
1336
  rows: 2,
1087
1337
  placeholder: "Ask the agent to edit text, image URLs, or theme tokens",
1088
- className: "flex-1 resize-none rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] leading-4 text-stone-900 outline-none placeholder:text-stone-500 focus:border-stone-500"
1338
+ className: overlayClass(
1339
+ "composerInput",
1340
+ "flex-1 resize-none rounded border border-stone-300 bg-[#f4efe6] px-2 py-1.5 text-[12px] leading-4 text-stone-900 outline-none placeholder:text-stone-500 focus:border-stone-500"
1341
+ )
1089
1342
  }
1090
1343
  ),
1091
1344
  /* @__PURE__ */ jsx3(
@@ -1094,7 +1347,10 @@ function OverlayChatPanel({
1094
1347
  type: "button",
1095
1348
  onClick: onSend,
1096
1349
  disabled: !isAuthenticated || sending || !message.trim(),
1097
- className: "rounded border border-stone-500 bg-stone-600 px-3 py-1.5 text-[12px] font-semibold text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50",
1350
+ className: overlayClass(
1351
+ "sendButton",
1352
+ "rounded border border-stone-500 bg-stone-600 px-3 py-1.5 text-[12px] font-semibold text-stone-100 hover:bg-stone-700 disabled:cursor-not-allowed disabled:opacity-50"
1353
+ ),
1098
1354
  children: sending ? "Sending" : "Send"
1099
1355
  }
1100
1356
  )
@@ -1109,24 +1365,30 @@ function OverlayHistoryPanel({
1109
1365
  onRestoreCheckpoint,
1110
1366
  onDeleteCheckpoint
1111
1367
  }) {
1112
- return /* @__PURE__ */ jsx3("section", { className: "flex min-h-0 flex-1 flex-col p-2 text-[11px] leading-4", children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-2 overflow-hidden", children: [
1113
- /* @__PURE__ */ jsxs("div", { className: "rounded border border-stone-300 bg-[#f8f3e9]", children: [
1114
- /* @__PURE__ */ jsxs("div", { className: "border-b border-stone-200 px-2 py-1 font-semibold text-stone-700", children: [
1368
+ return /* @__PURE__ */ jsx3("section", { className: overlayClass("historySection", "flex min-h-0 flex-1 flex-col p-2 text-[11px] leading-4"), children: /* @__PURE__ */ jsxs("div", { className: overlayClass("historyColumns", "flex min-h-0 flex-1 flex-col gap-2 overflow-hidden"), children: [
1369
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("historyCard", "rounded border border-stone-300 bg-[#f8f3e9]"), children: [
1370
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("historyCardTitle", "border-b border-stone-200 px-2 py-1 font-semibold text-stone-700"), children: [
1115
1371
  "Published (",
1116
1372
  history.published.length,
1117
1373
  ")"
1118
1374
  ] }),
1119
- /* @__PURE__ */ jsx3("div", { className: "max-h-40 overflow-auto px-2 py-1.5", children: history.published.length > 0 ? /* @__PURE__ */ jsx3("div", { className: "space-y-1", children: history.published.map((item) => /* @__PURE__ */ jsxs(
1375
+ /* @__PURE__ */ jsx3("div", { className: overlayClass("historyList", "max-h-40 overflow-auto px-2 py-1.5"), children: history.published.length > 0 ? /* @__PURE__ */ jsx3("div", { className: overlayClass("historyStack", "space-y-1"), children: history.published.map((item) => /* @__PURE__ */ jsxs(
1120
1376
  "div",
1121
1377
  {
1122
- className: "flex items-center justify-between gap-2 rounded border border-stone-200 bg-[#f2ecdf] px-2 py-1",
1378
+ className: overlayClass(
1379
+ "historyItem",
1380
+ "flex items-center justify-between gap-2 rounded border border-stone-200 bg-[#f2ecdf] px-2 py-1"
1381
+ ),
1123
1382
  children: [
1124
- /* @__PURE__ */ jsx3("span", { className: "truncate text-[10px] text-stone-700", children: formatHistoryTime(item.createdAt) }),
1383
+ /* @__PURE__ */ jsx3("span", { className: overlayClass("historyTimestamp", "truncate text-[10px] text-stone-700"), children: formatHistoryTime(item.createdAt) }),
1125
1384
  /* @__PURE__ */ jsx3(
1126
1385
  "button",
1127
1386
  {
1128
1387
  type: "button",
1129
- className: "rounded border border-stone-300 bg-[#f7f2e8] px-1.5 py-0.5 text-[10px] text-stone-700 hover:bg-[#efe8dc]",
1388
+ className: overlayClass(
1389
+ "historyAction",
1390
+ "rounded border border-stone-300 bg-[#f7f2e8] px-1.5 py-0.5 text-[10px] text-stone-700 hover:bg-[#efe8dc]"
1391
+ ),
1130
1392
  onClick: () => onRestorePublished(item),
1131
1393
  children: "Restore"
1132
1394
  }
@@ -1134,61 +1396,88 @@ function OverlayHistoryPanel({
1134
1396
  ]
1135
1397
  },
1136
1398
  `pub-${item.id}`
1137
- )) }) : /* @__PURE__ */ jsx3("p", { className: "text-[10px] text-stone-500", children: "No published snapshots." }) })
1399
+ )) }) : /* @__PURE__ */ jsx3("p", { className: overlayClass("emptyText", "text-[10px] text-stone-500"), children: "No published snapshots." }) })
1138
1400
  ] }),
1139
- /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col rounded border border-stone-300 bg-[#f8f3e9]", children: [
1140
- /* @__PURE__ */ jsxs("div", { className: "border-b border-stone-200 px-2 py-1 font-semibold text-stone-700", children: [
1141
- "Checkpoints (",
1142
- history.checkpoints.length,
1143
- ")"
1144
- ] }),
1145
- /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 overflow-auto px-2 py-1.5", children: history.checkpoints.length > 0 ? /* @__PURE__ */ jsx3("div", { className: "space-y-1", children: history.checkpoints.map((item) => /* @__PURE__ */ jsxs(
1146
- "div",
1147
- {
1148
- className: "flex items-start justify-between gap-2 rounded border border-stone-200 bg-[#f2ecdf] px-2 py-1",
1149
- children: [
1150
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1151
- /* @__PURE__ */ jsx3("p", { className: "truncate text-[10px] text-stone-700", children: formatHistoryTime(item.createdAt) }),
1152
- item.reason ? /* @__PURE__ */ jsx3("p", { className: "truncate text-[10px] text-stone-500", children: item.reason }) : null
1153
- ] }),
1154
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1155
- /* @__PURE__ */ jsx3(
1156
- "button",
1157
- {
1158
- type: "button",
1159
- disabled: deletingCheckpointId === item.id,
1160
- className: "rounded border border-stone-300 bg-[#f7f2e8] px-1.5 py-0.5 text-[10px] text-stone-700 hover:bg-[#efe8dc] disabled:cursor-not-allowed disabled:opacity-50",
1161
- onClick: () => onRestoreCheckpoint(item),
1162
- children: "Restore"
1163
- }
1401
+ /* @__PURE__ */ jsxs(
1402
+ "div",
1403
+ {
1404
+ className: overlayClass(
1405
+ "historyCard",
1406
+ "flex min-h-0 flex-1 flex-col rounded border border-stone-300 bg-[#f8f3e9]"
1407
+ ),
1408
+ children: [
1409
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("historyCardTitle", "border-b border-stone-200 px-2 py-1 font-semibold text-stone-700"), children: [
1410
+ "Checkpoints (",
1411
+ history.checkpoints.length,
1412
+ ")"
1413
+ ] }),
1414
+ /* @__PURE__ */ jsx3("div", { className: overlayClass("historyList", "min-h-0 flex-1 overflow-auto px-2 py-1.5"), children: history.checkpoints.length > 0 ? /* @__PURE__ */ jsx3("div", { className: overlayClass("historyStack", "space-y-1"), children: history.checkpoints.map((item) => /* @__PURE__ */ jsxs(
1415
+ "div",
1416
+ {
1417
+ className: overlayClass(
1418
+ "historyItemCheckpoint",
1419
+ "flex items-start justify-between gap-2 rounded border border-stone-200 bg-[#f2ecdf] px-2 py-1"
1164
1420
  ),
1165
- /* @__PURE__ */ jsx3(
1166
- "button",
1167
- {
1168
- type: "button",
1169
- "aria-label": "Delete checkpoint",
1170
- title: "Delete checkpoint",
1171
- disabled: deletingCheckpointId === item.id,
1172
- className: "inline-flex h-6 w-6 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] text-stone-700 hover:bg-[#efe8dc] disabled:cursor-not-allowed disabled:opacity-50",
1173
- onClick: () => onDeleteCheckpoint(item),
1174
- children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 20 20", fill: "none", className: "h-3.5 w-3.5", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
1175
- "path",
1421
+ children: [
1422
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("historyTextBlock", "min-w-0 flex-1"), children: [
1423
+ /* @__PURE__ */ jsx3("p", { className: overlayClass("historyTimestamp", "truncate text-[10px] text-stone-700"), children: formatHistoryTime(item.createdAt) }),
1424
+ item.reason ? /* @__PURE__ */ jsx3("p", { className: overlayClass("historyReason", "truncate text-[10px] text-stone-500"), children: item.reason }) : null
1425
+ ] }),
1426
+ /* @__PURE__ */ jsxs("div", { className: overlayClass("historyActions", "flex items-center gap-1"), children: [
1427
+ /* @__PURE__ */ jsx3(
1428
+ "button",
1176
1429
  {
1177
- d: "M4.5 5.5H15.5M8 3.75H12M7 7.5V13.5M10 7.5V13.5M13 7.5V13.5M6.5 5.5L7 15C7.03 15.6 7.53 16.08 8.13 16.08H11.87C12.47 16.08 12.97 15.6 13 15L13.5 5.5",
1178
- stroke: "currentColor",
1179
- strokeWidth: "1.4",
1180
- strokeLinecap: "round",
1181
- strokeLinejoin: "round"
1430
+ type: "button",
1431
+ disabled: deletingCheckpointId === item.id,
1432
+ className: overlayClass(
1433
+ "historyAction",
1434
+ "rounded border border-stone-300 bg-[#f7f2e8] px-1.5 py-0.5 text-[10px] text-stone-700 hover:bg-[#efe8dc] disabled:cursor-not-allowed disabled:opacity-50"
1435
+ ),
1436
+ onClick: () => onRestoreCheckpoint(item),
1437
+ children: "Restore"
1182
1438
  }
1183
- ) })
1184
- }
1185
- )
1186
- ] })
1187
- ]
1188
- },
1189
- `cp-${item.id}`
1190
- )) }) : /* @__PURE__ */ jsx3("p", { className: "text-[10px] text-stone-500", children: "No checkpoints yet." }) })
1191
- ] })
1439
+ ),
1440
+ /* @__PURE__ */ jsx3(
1441
+ "button",
1442
+ {
1443
+ type: "button",
1444
+ "aria-label": "Delete checkpoint",
1445
+ title: "Delete checkpoint",
1446
+ disabled: deletingCheckpointId === item.id,
1447
+ className: overlayClass(
1448
+ "historyDelete",
1449
+ "inline-flex h-6 w-6 items-center justify-center rounded border border-stone-300 bg-[#f7f2e8] text-stone-700 hover:bg-[#efe8dc] disabled:cursor-not-allowed disabled:opacity-50"
1450
+ ),
1451
+ onClick: () => onDeleteCheckpoint(item),
1452
+ children: /* @__PURE__ */ jsx3(
1453
+ "svg",
1454
+ {
1455
+ viewBox: "0 0 20 20",
1456
+ fill: "none",
1457
+ className: overlayClass("icon", "h-3.5 w-3.5"),
1458
+ "aria-hidden": "true",
1459
+ children: /* @__PURE__ */ jsx3(
1460
+ "path",
1461
+ {
1462
+ d: "M4.5 5.5H15.5M8 3.75H12M7 7.5V13.5M10 7.5V13.5M13 7.5V13.5M6.5 5.5L7 15C7.03 15.6 7.53 16.08 8.13 16.08H11.87C12.47 16.08 12.97 15.6 13 15L13.5 5.5",
1463
+ stroke: "currentColor",
1464
+ strokeWidth: "1.4",
1465
+ strokeLinecap: "round",
1466
+ strokeLinejoin: "round"
1467
+ }
1468
+ )
1469
+ }
1470
+ )
1471
+ }
1472
+ )
1473
+ ] })
1474
+ ]
1475
+ },
1476
+ `cp-${item.id}`
1477
+ )) }) : /* @__PURE__ */ jsx3("p", { className: overlayClass("emptyText", "text-[10px] text-stone-500"), children: "No checkpoints yet." }) })
1478
+ ]
1479
+ }
1480
+ )
1192
1481
  ] }) });
1193
1482
  }
1194
1483
  function OverlayLauncherButton({ onOpen }) {
@@ -1197,13 +1486,74 @@ function OverlayLauncherButton({ onOpen }) {
1197
1486
  {
1198
1487
  type: "button",
1199
1488
  onClick: onOpen,
1200
- className: "fixed bottom-4 right-4 z-[100] rounded-full border border-stone-600 bg-stone-700 px-4 py-2 text-[12px] font-semibold text-stone-100 shadow-xl hover:bg-stone-800",
1489
+ className: overlayClass(
1490
+ "launcherButton",
1491
+ "fixed bottom-4 right-4 z-[100] rounded-full border border-stone-600 bg-stone-700 px-4 py-2 text-[12px] font-semibold text-stone-100 shadow-xl hover:bg-stone-800"
1492
+ ),
1201
1493
  style: { fontFamily: OVERLAY_FONT_FAMILY },
1202
1494
  children: "Chat to Webmaster"
1203
1495
  }
1204
1496
  );
1205
1497
  }
1206
1498
 
1499
+ // src/overlay/core-styles.ts
1500
+ var OVERLAY_CORE_STYLE_ID = "wmd-core-styles";
1501
+ var OVERLAY_CORE_STYLE_TEXT = `
1502
+ .wmd-panel{position:fixed;right:1rem;bottom:1rem;z-index:100;display:flex;flex-direction:column;width:min(480px,calc(100vw - 1.5rem));height:62vh;max-height:calc(100vh - 1.5rem);overflow:hidden;box-sizing:border-box}
1503
+ .wmd-panel *{box-sizing:border-box}
1504
+ .wmd-launcher{position:fixed;right:1rem;bottom:1rem;z-index:100;box-sizing:border-box}
1505
+ .wmd-header{flex-shrink:0}
1506
+ .wmd-header-row{display:flex;align-items:center;gap:.5rem}
1507
+ .wmd-header-actions{margin-left:auto;display:flex;align-items:center;gap:.25rem}
1508
+ .wmd-tabs{display:inline-flex;align-items:center}
1509
+ .wmd-login-section{display:flex;flex:1;min-height:0;align-items:center;justify-content:center}
1510
+ .wmd-login-card,.wmd-login-warning{width:100%;max-width:24rem}
1511
+ .wmd-login-fields{display:flex;flex-direction:column;gap:.5rem}
1512
+ .wmd-chat-section{display:flex;flex:1;min-height:0;flex-direction:column;gap:.25rem;overflow:auto}
1513
+ .wmd-message--tool{max-width:96%}
1514
+ .wmd-message--user,.wmd-message--thinking,.wmd-message--assistant,.wmd-message--fallback{max-width:92%}
1515
+ .wmd-message--user{margin-left:auto}
1516
+ .wmd-message--assistant{position:relative}
1517
+ .wmd-assistant-avatar,.wmd-assistant-avatar-fallback{position:absolute;top:.375rem;left:.5rem;width:18px;height:18px}
1518
+ .wmd-assistant-avatar--pending{animation:wmd-pulse 2s cubic-bezier(.4,0,.6,1) infinite}
1519
+ .wmd-footer{flex-shrink:0}
1520
+ .wmd-model-row,.wmd-selected-element,.wmd-composer-row{display:flex;align-items:center;gap:.375rem}
1521
+ .wmd-model-select,.wmd-composer-input{min-width:0;flex:1}
1522
+ .wmd-composer-input{resize:none}
1523
+ .wmd-history-section{display:flex;flex:1;min-height:0;flex-direction:column}
1524
+ .wmd-history-columns{display:flex;flex:1;min-height:0;flex-direction:column;gap:.5rem;overflow:hidden}
1525
+ .wmd-history-card{display:flex;min-height:0;flex-direction:column}
1526
+ .wmd-history-list{overflow:auto}
1527
+ .wmd-history-stack{display:flex;flex-direction:column;gap:.25rem}
1528
+ .wmd-history-item{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
1529
+ .wmd-history-item--checkpoint{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem}
1530
+ .wmd-history-text{min-width:0;flex:1}
1531
+ .wmd-history-actions{display:flex;align-items:center;gap:.25rem}
1532
+ .wmd-history-timestamp,.wmd-history-reason,.wmd-selected-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1533
+ .wmd-icon-button,.wmd-selected-clear,.wmd-history-delete{display:inline-flex;align-items:center;justify-content:center}
1534
+ .wmd-icon{width:14px;height:14px}
1535
+ .wmd-selected-clear-icon{width:12px;height:12px}
1536
+ @media (max-width:640px){.wmd-panel{left:.75rem;right:.75rem;bottom:.75rem;width:auto;height:min(72vh,540px)}}
1537
+ @keyframes wmd-pulse{50%{opacity:.5}}
1538
+ `.trim();
1539
+ function ensureOverlayCoreStyles(doc) {
1540
+ const target = doc ?? (typeof document !== "undefined" ? document : void 0);
1541
+ if (!target) {
1542
+ return;
1543
+ }
1544
+ if (target.getElementById(OVERLAY_CORE_STYLE_ID)) {
1545
+ return;
1546
+ }
1547
+ const mountTarget = target.head ?? target.documentElement;
1548
+ if (!mountTarget) {
1549
+ return;
1550
+ }
1551
+ const styleElement = target.createElement("style");
1552
+ styleElement.id = OVERLAY_CORE_STYLE_ID;
1553
+ styleElement.textContent = OVERLAY_CORE_STYLE_TEXT;
1554
+ mountTarget.appendChild(styleElement);
1555
+ }
1556
+
1207
1557
  // src/overlay/controller.ts
1208
1558
  import {
1209
1559
  useCallback,
@@ -1634,8 +1984,14 @@ Reason: ${checkpoint.reason}` : "";
1634
1984
 
1635
1985
  // src/overlay.tsx
1636
1986
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1637
- function WebmasterDroidOverlay() {
1987
+ function WebmasterDroidOverlay({ injectCoreStyles = true }) {
1638
1988
  const controller = useOverlayController();
1989
+ useEffect3(() => {
1990
+ if (!injectCoreStyles) {
1991
+ return;
1992
+ }
1993
+ ensureOverlayCoreStyles();
1994
+ }, [injectCoreStyles]);
1639
1995
  if (!controller.isAdminMode) {
1640
1996
  return null;
1641
1997
  }
@@ -1644,7 +2000,10 @@ function WebmasterDroidOverlay() {
1644
2000
  {
1645
2001
  ref: controller.overlayRootRef,
1646
2002
  "data-admin-overlay-root": true,
1647
- className: "fixed bottom-4 right-4 z-[100] flex h-[62vh] w-[min(480px,calc(100vw-1.5rem))] flex-col overflow-hidden rounded-lg border border-stone-300 bg-[#f6f2eb] text-stone-900 shadow-2xl",
2003
+ className: overlayClass(
2004
+ "panel",
2005
+ "fixed bottom-4 right-4 z-[100] flex h-[62vh] w-[min(480px,calc(100vw-1.5rem))] flex-col overflow-hidden rounded-lg border border-stone-300 bg-[#f6f2eb] text-stone-900 shadow-2xl"
2006
+ ),
1648
2007
  style: { fontFamily: OVERLAY_FONT_FAMILY },
1649
2008
  children: [
1650
2009
  /* @__PURE__ */ jsx4(
@@ -1731,7 +2090,7 @@ function WebmasterDroidOverlay() {
1731
2090
  import {
1732
2091
  createContext as createContext3,
1733
2092
  useContext as useContext3,
1734
- useEffect as useEffect3,
2093
+ useEffect as useEffect4,
1735
2094
  useMemo as useMemo3,
1736
2095
  useState as useState3
1737
2096
  } from "react";
@@ -1770,7 +2129,7 @@ function CmsRuntimeBridge(props) {
1770
2129
  document: defaultDocument,
1771
2130
  error: null
1772
2131
  });
1773
- useEffect3(() => {
2132
+ useEffect4(() => {
1774
2133
  let ignore = false;
1775
2134
  fetchCmsContent(config.apiBaseUrl, stage, token).then((content2) => {
1776
2135
  if (ignore) {
@@ -1810,7 +2169,7 @@ function CmsRuntimeBridge(props) {
1810
2169
  const content = props.applyThemeTokens ? /* @__PURE__ */ jsx5("div", { style: createThemeCssVariables(value.document.themeTokens), children: props.children }) : props.children;
1811
2170
  return /* @__PURE__ */ jsxs3(CmsRuntimeContext.Provider, { value, children: [
1812
2171
  /* @__PURE__ */ jsx5(EditableProvider, { document: value.document, mode: stage, enabled: isAdminMode, children: content }),
1813
- props.includeOverlay ? /* @__PURE__ */ jsx5(WebmasterDroidOverlay, {}) : null
2172
+ props.includeOverlay ? /* @__PURE__ */ jsx5(WebmasterDroidOverlay, { injectCoreStyles: props.injectCoreStyles }) : null
1814
2173
  ] });
1815
2174
  }
1816
2175
  function WebmasterDroidRuntime(props) {
@@ -1820,6 +2179,7 @@ function WebmasterDroidRuntime(props) {
1820
2179
  fallbackDocument: props.fallbackDocument,
1821
2180
  includeOverlay: props.includeOverlay ?? true,
1822
2181
  applyThemeTokens: props.applyThemeTokens ?? true,
2182
+ injectCoreStyles: props.injectCoreStyles ?? true,
1823
2183
  children: props.children
1824
2184
  }
1825
2185
  ) });