pxengine 0.1.117 → 0.1.119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -16129,6 +16129,10 @@ var RefreshIcon = () => /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("svg", {
16129
16129
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("polyline", { points: "23 4 23 10 17 10" }),
16130
16130
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
16131
16131
  ] });
16132
+ var EditIcon = () => /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16133
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
16134
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
16135
+ ] });
16132
16136
  var SlideTypeIcon = () => /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16133
16137
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("rect", { x: "3", y: "4", width: "18", height: "14", rx: "2" }),
16134
16138
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
@@ -16139,6 +16143,7 @@ function formatTemplateLabel(templateId) {
16139
16143
  if (!templateId) return null;
16140
16144
  return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
16141
16145
  }
16146
+ var Chip = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "inline-flex items-center px-2 h-[22px] rounded-md bg-zinc-800/70 border border-zinc-700/50 text-[11px] font-medium text-zinc-400 whitespace-nowrap", children });
16142
16147
  function deriveJobStatusUrl(newJobId, pollUrl, regenerateUrl) {
16143
16148
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/presentations\/[^/]+\/regenerate.*$/, "") ?? "";
16144
16149
  return `${base}/api/jobs/${newJobId}/status`;
@@ -16166,7 +16171,7 @@ var FORMATS = [
16166
16171
  ext: ".html",
16167
16172
  emoji: "\u{1F310}",
16168
16173
  desc: "Interactive web presentation \u2014 download and open in browser",
16169
- accent: { text: "text-indigo-400", bg: "bg-indigo-500/10 border-indigo-500/20" }
16174
+ accent: { text: "text-sky-400", bg: "bg-sky-500/10 border-sky-500/20" }
16170
16175
  }
16171
16176
  ];
16172
16177
  var ExportModal = ({ formats, title, onClose }) => {
@@ -16283,7 +16288,7 @@ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) =>
16283
16288
  return /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "fixed inset-0 z-50 bg-black flex flex-col", children: [
16284
16289
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center justify-between gap-4 px-4 h-11 bg-zinc-950/90 border-b border-zinc-800/60 flex-shrink-0", children: [
16285
16290
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center gap-3 min-w-0", children: [
16286
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-indigo-400 flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(SlidesIcon, {}) }),
16291
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-[#DCC99B] flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(SlidesIcon, {}) }),
16287
16292
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-sm font-medium text-zinc-300 truncate", children: title }),
16288
16293
  slideCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("span", { className: "text-xs text-zinc-600 flex-shrink-0", children: [
16289
16294
  currentSlide,
@@ -16297,7 +16302,7 @@ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) =>
16297
16302
  {
16298
16303
  onClick: () => sendSlideCommand("prevSlide"),
16299
16304
  disabled: !iframeReady,
16300
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
16305
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-[#C0AE82] hover:text-[#DCC99B] text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
16301
16306
  "aria-label": "Previous slide",
16302
16307
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronLeft2, {})
16303
16308
  }
@@ -16307,7 +16312,7 @@ var FullscreenModal = ({ url, title, slideCount, initialSlide = 1, onClose }) =>
16307
16312
  {
16308
16313
  onClick: () => sendSlideCommand("nextSlide"),
16309
16314
  disabled: !iframeReady,
16310
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
16315
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-[#C0AE82] hover:text-[#DCC99B] text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
16311
16316
  "aria-label": "Next slide",
16312
16317
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronRight2, {})
16313
16318
  }
@@ -16883,11 +16888,11 @@ var PresentationJobCard = ({
16883
16888
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
16884
16889
  "div",
16885
16890
  {
16886
- className: "h-[3px] bg-gradient-to-r from-indigo-500 via-purple-500 to-indigo-500 bg-[length:200%_100%] animate-[gradient-shift_2s_ease-in-out_infinite]",
16891
+ className: "h-[3px]",
16887
16892
  style: {
16893
+ backgroundImage: accentGradient || "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B, #C0AE82, #8B7D5E)",
16888
16894
  backgroundSize: "200% 100%",
16889
- animation: "gradient-shift 2s ease-in-out infinite",
16890
- ...accentGradient ? { backgroundImage: accentGradient } : {}
16895
+ animation: "gradient-shift 2s ease-in-out infinite"
16891
16896
  }
16892
16897
  }
16893
16898
  ),
@@ -16896,7 +16901,7 @@ var PresentationJobCard = ({
16896
16901
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
16897
16902
  "div",
16898
16903
  {
16899
- className: "w-10 h-10 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center flex-shrink-0",
16904
+ className: "w-10 h-10 rounded-xl bg-[#C0AE82]/10 border border-[#C0AE82]/25 flex items-center justify-center flex-shrink-0",
16900
16905
  style: { ...t.accentSubtle(0.1), ...t.accentBorder },
16901
16906
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-lg", children: getPhaseIcon() })
16902
16907
  }
@@ -16914,10 +16919,11 @@ var PresentationJobCard = ({
16914
16919
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("div", { className: "h-2 bg-zinc-800 rounded-full overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
16915
16920
  "div",
16916
16921
  {
16917
- className: "h-full bg-gradient-to-r from-indigo-500 to-purple-500 rounded-full transition-all duration-500 ease-out",
16922
+ className: "h-full rounded-full transition-all duration-500 ease-out",
16918
16923
  style: {
16919
16924
  width: `${Math.max(pct, 2)}%`,
16920
- ...accentGradient ? { backgroundImage: accentGradient } : t.accentBg
16925
+ backgroundImage: accentGradient || "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)",
16926
+ ...!accentGradient ? t.accentBg : {}
16921
16927
  }
16922
16928
  }
16923
16929
  ) }),
@@ -16927,7 +16933,7 @@ var PresentationJobCard = ({
16927
16933
  ] })
16928
16934
  ] }),
16929
16935
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center gap-2", children: [
16930
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("div", { className: "w-2 h-2 rounded-full bg-indigo-500 animate-pulse", style: t.accentBg }),
16936
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("div", { className: "w-2 h-2 rounded-full bg-[#C0AE82] animate-pulse", style: t.accentBg }),
16931
16937
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-xs text-zinc-400", children: step })
16932
16938
  ] }),
16933
16939
  phase === "ai_generation" && slidesTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center gap-2 pt-1", children: [
@@ -16936,7 +16942,7 @@ var PresentationJobCard = ({
16936
16942
  {
16937
16943
  className: cn(
16938
16944
  "w-6 h-1.5 rounded-full transition-all duration-300",
16939
- i < slidesCompleted ? "bg-indigo-500" : i === slidesCompleted ? "bg-indigo-500/50 animate-pulse" : "bg-zinc-700"
16945
+ i < slidesCompleted ? "bg-[#C0AE82]" : i === slidesCompleted ? "bg-[#C0AE82]/50 animate-pulse" : "bg-zinc-700"
16940
16946
  )
16941
16947
  },
16942
16948
  i
@@ -16984,7 +16990,7 @@ var PresentationJobCard = ({
16984
16990
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
16985
16991
  "div",
16986
16992
  {
16987
- className: "w-10 h-10 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center flex-shrink-0 text-indigo-400",
16993
+ className: "w-10 h-10 rounded-xl bg-[#C0AE82]/10 border border-[#C0AE82]/25 flex items-center justify-center flex-shrink-0 text-[#DCC99B]",
16988
16994
  style: { ...t.accentSubtle(0.1), ...t.accentBorder, ...t.accent },
16989
16995
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(SlidesIcon, {})
16990
16996
  }
@@ -17021,7 +17027,7 @@ var PresentationJobCard = ({
17021
17027
  onChange: (e) => setSlideTemplate(i, e.target.value),
17022
17028
  disabled: rowBusy,
17023
17029
  title: "Design template for this slide only (default: deck's template)",
17024
- className: "w-24 flex-shrink-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-1.5 h-8 text-[10px] text-zinc-300 focus:border-indigo-500 outline-none disabled:opacity-60",
17030
+ className: "w-24 flex-shrink-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-1.5 h-8 text-[10px] text-zinc-300 focus:border-[#C0AE82] outline-none disabled:opacity-60",
17025
17031
  children: [
17026
17032
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("option", { value: "", children: "Deck default" }),
17027
17033
  slideTemplateOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("option", { value: opt.id, children: opt.name }, opt.id))
@@ -17034,7 +17040,7 @@ var PresentationJobCard = ({
17034
17040
  value: messageEdits[i] ?? s.message ?? "",
17035
17041
  onChange: (e) => setMessageEdits((prev) => ({ ...prev, [i]: e.target.value })),
17036
17042
  disabled: building,
17037
- className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-indigo-500 outline-none disabled:opacity-60"
17043
+ className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-[#C0AE82] outline-none disabled:opacity-60"
17038
17044
  }
17039
17045
  ),
17040
17046
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
@@ -17109,34 +17115,88 @@ var PresentationJobCard = ({
17109
17115
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
17110
17116
  "div",
17111
17117
  {
17112
- className: "w-10 h-10 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center flex-shrink-0 text-indigo-400",
17118
+ className: "w-10 h-10 rounded-xl bg-[#C0AE82]/10 border border-[#C0AE82]/25 flex items-center justify-center flex-shrink-0 text-[#DCC99B]",
17113
17119
  style: { ...t.accentSubtle(0.1), ...t.accentBorder, ...t.accent },
17114
17120
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(SlidesIcon, {})
17115
17121
  }
17116
17122
  ),
17117
17123
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex-1 min-w-0", children: [
17118
17124
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", style: t.text, children: title }),
17119
- /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("p", { className: "text-xs text-zinc-500 mt-0.5", style: t.muted, children: [
17120
- slideCount ? `${slideCount} slides` : "Presentation",
17121
- " \xB7 Ready to export",
17122
- templateLabel && ` \xB7 ${templateLabel}`
17125
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5 mt-1.5", children: [
17126
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(Chip, { children: slideCount ? `${slideCount} slides` : "Presentation" }),
17127
+ templateLabel && /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(Chip, { children: templateLabel })
17123
17128
  ] }),
17124
- generationMode === "template" && /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-emerald-400/90", children: "Approved \u2014 future decks use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-amber-400/90", children: "Review this deck, then approve to lock the format" }) : null })
17129
+ generationMode === "template" && (isApproved || reviewStatus === "pending_review") && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("p", { className: "flex items-center gap-1.5 text-xs mt-2", children: [
17130
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
17131
+ "span",
17132
+ {
17133
+ className: cn(
17134
+ "w-1.5 h-1.5 rounded-full flex-shrink-0",
17135
+ isApproved ? "bg-emerald-400" : "bg-amber-400"
17136
+ )
17137
+ }
17138
+ ),
17139
+ isApproved ? /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-emerald-400/90", children: "Approved \u2014 future decks use this format" }) : /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "text-amber-400/90", children: "Review this deck, then approve to lock the format" })
17140
+ ] })
17125
17141
  ] }),
17126
17142
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
17127
- canRegenerate && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17128
- "button",
17129
- {
17130
- onClick: handleRegenerate,
17131
- disabled: regenerating || approving,
17132
- title: "Try another design template with the same content",
17133
- className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-300 text-xs font-medium transition-colors disabled:opacity-50",
17134
- children: [
17135
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(RefreshIcon, {}),
17136
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: regenerating ? "Switching..." : "Regenerate" })
17137
- ]
17138
- }
17139
- ),
17143
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)("div", { className: "flex items-center rounded-lg border border-zinc-700 bg-zinc-800 overflow-hidden divide-x divide-zinc-700", children: [
17144
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17145
+ "a",
17146
+ {
17147
+ href: hasHtml ? `/presentations/${_job_id}/edit` : void 0,
17148
+ "aria-disabled": !hasHtml,
17149
+ title: "Edit presentation content",
17150
+ className: cn(
17151
+ "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors",
17152
+ !hasHtml && "pointer-events-none opacity-40"
17153
+ ),
17154
+ children: [
17155
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(EditIcon, {}),
17156
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: "Edit" })
17157
+ ]
17158
+ }
17159
+ ),
17160
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17161
+ "button",
17162
+ {
17163
+ onClick: () => setShowFullscreen(true),
17164
+ disabled: !hasHtml,
17165
+ title: "Open fullscreen preview",
17166
+ className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
17167
+ children: [
17168
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ExpandIcon, {}),
17169
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: "Preview" })
17170
+ ]
17171
+ }
17172
+ ),
17173
+ canRegenerate && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17174
+ "button",
17175
+ {
17176
+ onClick: handleRegenerate,
17177
+ disabled: regenerating || approving,
17178
+ title: "Try another design template with the same content",
17179
+ className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors disabled:opacity-40",
17180
+ children: [
17181
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(RefreshIcon, {}),
17182
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: regenerating ? "Switching\u2026" : "Regenerate" })
17183
+ ]
17184
+ }
17185
+ ),
17186
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
17187
+ "button",
17188
+ {
17189
+ onClick: handleShare,
17190
+ disabled: !hasHtml,
17191
+ title: copied ? "Copied!" : "Copy shareable link",
17192
+ className: cn(
17193
+ "flex items-center justify-center w-7 h-7 transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17194
+ copied ? "text-green-400" : "text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60"
17195
+ ),
17196
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ShareIcon, {})
17197
+ }
17198
+ )
17199
+ ] }),
17140
17200
  canApprove && /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17141
17201
  "button",
17142
17202
  {
@@ -17151,39 +17211,16 @@ var PresentationJobCard = ({
17151
17211
  }
17152
17212
  ),
17153
17213
  isApproved && /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { className: "flex items-center justify-center w-7 h-7 rounded-lg border border-emerald-500/40 bg-emerald-500/10 text-emerald-400", title: "Format saved", children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(CheckIcon, {}) }),
17154
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(
17155
- "button",
17156
- {
17157
- onClick: handleShare,
17158
- disabled: !hasHtml,
17159
- title: copied ? "Copied!" : "Copy shareable link",
17160
- className: cn(
17161
- "w-7 h-7 rounded-lg border flex items-center justify-center transition-all",
17162
- copied ? "border-green-500/40 bg-green-500/10 text-green-400" : "border-zinc-700 bg-zinc-800 text-zinc-400 hover:border-zinc-500 hover:text-zinc-200",
17163
- "disabled:opacity-30 disabled:cursor-not-allowed"
17164
- ),
17165
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ShareIcon, {})
17166
- }
17167
- ),
17168
- /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17169
- "button",
17170
- {
17171
- onClick: () => setShowFullscreen(true),
17172
- disabled: !hasHtml,
17173
- title: "Open fullscreen preview",
17174
- className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-400 hover:text-zinc-200 text-xs font-medium transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17175
- children: [
17176
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ExpandIcon, {}),
17177
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: "Preview" })
17178
- ]
17179
- }
17180
- ),
17181
17214
  /* @__PURE__ */ (0, import_jsx_runtime147.jsxs)(
17182
17215
  "button",
17183
17216
  {
17184
17217
  onClick: () => setShowExport(true),
17185
- className: "flex items-center gap-1.5 px-2.5 h-7 bg-indigo-600 hover:bg-indigo-500 active:bg-indigo-700 text-white text-xs font-medium rounded-lg transition-colors",
17186
- style: { ...t.accentBg, ...t.accentText },
17218
+ className: "flex items-center gap-1.5 px-3 h-7 text-xs font-semibold rounded-lg transition-colors",
17219
+ style: {
17220
+ backgroundImage: accentGradient || "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)",
17221
+ color: "#0A0A0A",
17222
+ ...accentGradient ? t.accentText : {}
17223
+ },
17187
17224
  children: [
17188
17225
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(DownloadIcon, {}),
17189
17226
  /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("span", { children: "Export" })
@@ -17238,7 +17275,7 @@ var PresentationJobCard = ({
17238
17275
  sendSlideCommand("prevSlide");
17239
17276
  },
17240
17277
  disabled: !hasHtml || !iframeReady,
17241
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17278
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-[#C0AE82] hover:text-[#DCC99B] text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17242
17279
  "aria-label": "Previous slide",
17243
17280
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronLeft2, {})
17244
17281
  }
@@ -17256,7 +17293,7 @@ var PresentationJobCard = ({
17256
17293
  sendSlideCommand("nextSlide");
17257
17294
  },
17258
17295
  disabled: !hasHtml || !iframeReady,
17259
- className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-indigo-500 hover:text-indigo-400 text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17296
+ className: "w-7 h-7 rounded-full border border-zinc-700 bg-zinc-800 hover:border-[#C0AE82] hover:text-[#DCC99B] text-zinc-400 flex items-center justify-center transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
17260
17297
  "aria-label": "Next slide",
17261
17298
  children: /* @__PURE__ */ (0, import_jsx_runtime147.jsx)(ChevronRight2, {})
17262
17299
  }
@@ -17283,10 +17320,11 @@ var PresentationJobCard = ({
17283
17320
  var import_react79 = require("react");
17284
17321
  var import_jsx_runtime148 = require("react/jsx-runtime");
17285
17322
  var DEFAULT_THEME = {
17286
- primary: "#8b5cf6",
17287
- secondary: "#a78bfa",
17288
- accent: "#c4b5fd"
17323
+ primary: "#C0AE82",
17324
+ secondary: "#C4AD7C",
17325
+ accent: "#DCC99B"
17289
17326
  };
17327
+ var GOLD_GRADIENT = "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)";
17290
17328
  function readableOn(bg) {
17291
17329
  if (!bg || typeof bg !== "string") return "#ffffff";
17292
17330
  const hex = bg.replace("#", "");
@@ -17333,6 +17371,10 @@ var RefreshIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg",
17333
17371
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("polyline", { points: "23 4 23 10 17 10" }),
17334
17372
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
17335
17373
  ] });
17374
+ var EditIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
17375
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
17376
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
17377
+ ] });
17336
17378
  function formatTemplateLabel2(templateId) {
17337
17379
  if (!templateId) return null;
17338
17380
  return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
@@ -17354,7 +17396,7 @@ var FullscreenPreviewModal = ({ url, title, onClose }) => {
17354
17396
  return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "fixed inset-0 z-50 bg-black flex flex-col", children: [
17355
17397
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center justify-between gap-4 px-4 h-11 bg-zinc-950/90 border-b border-zinc-800/60 flex-shrink-0", children: [
17356
17398
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center gap-3 min-w-0", children: [
17357
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-violet-400 flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DocumentIcon, {}) }),
17399
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-[#DCC99B] flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DocumentIcon, {}) }),
17358
17400
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-sm font-medium text-zinc-300 truncate", children: title })
17359
17401
  ] }),
17360
17402
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
@@ -17380,6 +17422,102 @@ var FullscreenPreviewModal = ({ url, title, onClose }) => {
17380
17422
  ) })
17381
17423
  ] });
17382
17424
  };
17425
+ var Chip2 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "inline-flex items-center px-2 h-[22px] rounded-md bg-zinc-800/70 border border-zinc-700/50 text-[11px] font-medium text-zinc-400 whitespace-nowrap capitalize", children });
17426
+ var REPORT_FORMATS = [
17427
+ {
17428
+ key: "pdf",
17429
+ label: "PDF",
17430
+ ext: ".pdf",
17431
+ emoji: "\u{1F4C4}",
17432
+ desc: "Print-ready, fixed layout \u2014 open in any PDF viewer",
17433
+ accent: { text: "text-red-400", bg: "bg-red-500/10 border-red-500/20" }
17434
+ },
17435
+ {
17436
+ key: "html",
17437
+ label: "HTML",
17438
+ ext: ".html",
17439
+ emoji: "\u{1F310}",
17440
+ desc: "Interactive web page \u2014 download and open in a browser",
17441
+ accent: { text: "text-sky-400", bg: "bg-sky-500/10 border-sky-500/20" }
17442
+ }
17443
+ ];
17444
+ var ReportExportModal = ({ htmlUrl, pdfUrl, title, onClose }) => {
17445
+ const urls = { pdf: pdfUrl, html: htmlUrl };
17446
+ const available = REPORT_FORMATS.filter((f) => urls[f.key]);
17447
+ const filename = (title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase();
17448
+ const [downloadingKey, setDownloadingKey] = (0, import_react79.useState)(null);
17449
+ (0, import_react79.useEffect)(() => {
17450
+ const onKey = (e) => {
17451
+ if (e.key === "Escape") onClose();
17452
+ };
17453
+ document.addEventListener("keydown", onKey);
17454
+ return () => document.removeEventListener("keydown", onKey);
17455
+ }, [onClose]);
17456
+ const handleDownload = async (key, url, ext) => {
17457
+ if (downloadingKey) return;
17458
+ const downloadName = `${filename}${ext}`;
17459
+ const href = `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(downloadName)}`;
17460
+ try {
17461
+ setDownloadingKey(key);
17462
+ const response = await fetch(href);
17463
+ if (!response.ok) throw new Error(`status ${response.status}`);
17464
+ const blob = await response.blob();
17465
+ const objectUrl = window.URL.createObjectURL(blob);
17466
+ const anchor = document.createElement("a");
17467
+ anchor.href = objectUrl;
17468
+ anchor.download = downloadName;
17469
+ document.body.appendChild(anchor);
17470
+ anchor.click();
17471
+ anchor.remove();
17472
+ window.URL.revokeObjectURL(objectUrl);
17473
+ } catch {
17474
+ window.open(url, "_blank", "noopener,noreferrer");
17475
+ } finally {
17476
+ setDownloadingKey(null);
17477
+ }
17478
+ };
17479
+ return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [
17480
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "absolute inset-0 bg-black/70 backdrop-blur-sm", onClick: onClose }),
17481
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "relative z-10 bg-zinc-900 border border-zinc-800 rounded-2xl w-full max-w-sm p-6 shadow-2xl", children: [
17482
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-start justify-between mb-5", children: [
17483
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "min-w-0 pr-3", children: [
17484
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("h3", { className: "text-sm font-semibold text-zinc-100", children: "Download report" }),
17485
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5 truncate", children: title })
17486
+ ] }),
17487
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("button", { onClick: onClose, className: "text-zinc-500 hover:text-zinc-200 transition-colors flex-shrink-0 mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CloseIcon2, {}) })
17488
+ ] }),
17489
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "space-y-2.5", children: [
17490
+ available.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-sm text-zinc-500 text-center py-6", children: "No formats available yet" }),
17491
+ available.map((fmt) => {
17492
+ const url = urls[fmt.key];
17493
+ const isDownloading = downloadingKey === fmt.key;
17494
+ return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
17495
+ "button",
17496
+ {
17497
+ type: "button",
17498
+ disabled: Boolean(downloadingKey),
17499
+ onClick: () => handleDownload(fmt.key, url, fmt.ext),
17500
+ className: cn(
17501
+ "flex w-full items-center gap-3.5 p-3.5 rounded-xl border transition-all text-left",
17502
+ "hover:brightness-110 disabled:opacity-60 disabled:cursor-not-allowed",
17503
+ fmt.accent.bg
17504
+ ),
17505
+ children: [
17506
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-xl flex-shrink-0", children: fmt.emoji }),
17507
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex-1 min-w-0", children: [
17508
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: cn("text-sm font-semibold", fmt.accent.text), children: isDownloading ? `Downloading ${fmt.label}...` : fmt.label }),
17509
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs text-zinc-500 mt-0.5 leading-relaxed", children: isDownloading ? "Please wait while the file is being prepared." : fmt.desc })
17510
+ ] }),
17511
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: cn("flex-shrink-0", fmt.accent.text), children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DownloadIcon2, {}) })
17512
+ ]
17513
+ },
17514
+ fmt.key
17515
+ );
17516
+ })
17517
+ ] })
17518
+ ] })
17519
+ ] });
17520
+ };
17383
17521
  function deriveJobStatusUrl2(newJobId, pollUrl, regenerateUrl) {
17384
17522
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/reports\/[^/]+\/regenerate.*$/, "") ?? "";
17385
17523
  return `${base}/api/jobs/${newJobId}/status`;
@@ -17443,6 +17581,7 @@ var ResearchReportJobCard = (props) => {
17443
17581
  const [error, setError] = (0, import_react79.useState)(initialError);
17444
17582
  const [progress, setProgress] = (0, import_react79.useState)(initialProgress);
17445
17583
  const [showPreview, setShowPreview] = (0, import_react79.useState)(false);
17584
+ const [showExport, setShowExport] = (0, import_react79.useState)(false);
17446
17585
  const [previewScale, setPreviewScale] = (0, import_react79.useState)(1);
17447
17586
  const [copied, setCopied] = (0, import_react79.useState)(false);
17448
17587
  const [approving, setApproving] = (0, import_react79.useState)(false);
@@ -17835,8 +17974,9 @@ var ResearchReportJobCard = (props) => {
17835
17974
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
17836
17975
  "div",
17837
17976
  {
17838
- className: "h-[3px] bg-gradient-to-r from-violet-500 via-purple-500 to-violet-500",
17977
+ className: "h-[3px]",
17839
17978
  style: {
17979
+ backgroundImage: "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B, #C0AE82, #8B7D5E)",
17840
17980
  backgroundSize: "200% 100%",
17841
17981
  animation: "gradient-shift 2s ease-in-out infinite"
17842
17982
  }
@@ -17844,7 +17984,7 @@ var ResearchReportJobCard = (props) => {
17844
17984
  ),
17845
17985
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "p-5", children: [
17846
17986
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-start gap-3", children: [
17847
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-10 h-10 rounded-xl bg-violet-500/10 border border-violet-500/20 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-lg", children: getPhaseIcon() }) }),
17987
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-10 h-10 rounded-xl bg-[#C0AE82]/10 border border-[#C0AE82]/25 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-lg", children: getPhaseIcon() }) }),
17848
17988
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex-1 min-w-0", children: [
17849
17989
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title || "Generating Research Report" }),
17850
17990
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("p", { className: "text-xs text-zinc-500 mt-0.5", children: [
@@ -17859,8 +17999,8 @@ var ResearchReportJobCard = (props) => {
17859
17999
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "h-2 bg-zinc-800 rounded-full overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
17860
18000
  "div",
17861
18001
  {
17862
- className: "h-full bg-gradient-to-r from-violet-500 to-purple-500 rounded-full transition-all duration-500 ease-out",
17863
- style: { width: `${Math.max(pct, 2)}%` }
18002
+ className: "h-full rounded-full transition-all duration-500 ease-out",
18003
+ style: { width: `${Math.max(pct, 2)}%`, backgroundImage: GOLD_GRADIENT }
17864
18004
  }
17865
18005
  ) }),
17866
18006
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("span", { className: "absolute right-0 -top-5 text-xs text-zinc-500 font-medium tabular-nums", children: [
@@ -17869,7 +18009,7 @@ var ResearchReportJobCard = (props) => {
17869
18009
  ] })
17870
18010
  ] }),
17871
18011
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center gap-2", children: [
17872
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-2 h-2 rounded-full bg-violet-500 animate-pulse" }),
18012
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-2 h-2 rounded-full bg-[#C0AE82] animate-pulse" }),
17873
18013
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-xs text-zinc-400", children: step })
17874
18014
  ] }),
17875
18015
  phase === "ai_generation" && searchesTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "pt-1", children: [
@@ -17886,7 +18026,7 @@ var ResearchReportJobCard = (props) => {
17886
18026
  {
17887
18027
  className: cn(
17888
18028
  "flex-1 h-1 rounded-full transition-all duration-300",
17889
- i < searchesCompleted ? "bg-violet-500" : i === searchesCompleted ? "bg-violet-500/50 animate-pulse" : "bg-zinc-700"
18029
+ i < searchesCompleted ? "bg-[#C0AE82]" : i === searchesCompleted ? "bg-[#C0AE82]/50 animate-pulse" : "bg-zinc-700"
17890
18030
  )
17891
18031
  },
17892
18032
  i
@@ -17920,12 +18060,12 @@ var ResearchReportJobCard = (props) => {
17920
18060
  "div",
17921
18061
  {
17922
18062
  className: "h-[3px]",
17923
- style: { background: "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)" }
18063
+ style: { backgroundImage: GOLD_GRADIENT }
17924
18064
  }
17925
18065
  ),
17926
18066
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "p-5", children: [
17927
18067
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-start gap-3", children: [
17928
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-10 h-10 rounded-xl bg-violet-500/10 border border-violet-500/20 flex items-center justify-center flex-shrink-0 text-violet-300", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DocumentIcon, {}) }),
18068
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "w-10 h-10 rounded-xl bg-[#C0AE82]/10 border border-[#C0AE82]/25 flex items-center justify-center flex-shrink-0 text-[#DCC99B]", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DocumentIcon, {}) }),
17929
18069
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex-1 min-w-0", children: [
17930
18070
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title || "Report outline" }),
17931
18071
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("p", { className: "text-xs text-amber-400/90 mt-0.5", children: [
@@ -17946,7 +18086,7 @@ var ResearchReportJobCard = (props) => {
17946
18086
  value: headingEdits[i] ?? s.heading ?? "",
17947
18087
  onChange: (e) => setHeadingEdits((prev) => ({ ...prev, [i]: e.target.value })),
17948
18088
  disabled: building,
17949
- className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-violet-500 outline-none disabled:opacity-60"
18089
+ className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-[#C0AE82] outline-none disabled:opacity-60"
17950
18090
  }
17951
18091
  ),
17952
18092
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
@@ -18032,46 +18172,6 @@ var ResearchReportJobCard = (props) => {
18032
18172
  ] }) })
18033
18173
  ] }) });
18034
18174
  }
18035
- const handleDownload = async () => {
18036
- if (!htmlUrl) return;
18037
- const filename = `${(title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase()}.html`;
18038
- const href = `/api/download?url=${encodeURIComponent(htmlUrl)}&filename=${encodeURIComponent(filename)}`;
18039
- try {
18040
- const response = await fetch(href);
18041
- if (!response.ok) throw new Error(`status ${response.status}`);
18042
- const blob = await response.blob();
18043
- const objectUrl = window.URL.createObjectURL(blob);
18044
- const anchor = document.createElement("a");
18045
- anchor.href = objectUrl;
18046
- anchor.download = filename;
18047
- document.body.appendChild(anchor);
18048
- anchor.click();
18049
- anchor.remove();
18050
- window.URL.revokeObjectURL(objectUrl);
18051
- } catch {
18052
- window.open(htmlUrl, "_blank", "noopener,noreferrer");
18053
- }
18054
- };
18055
- const handleDownloadPdf = async () => {
18056
- if (!pdfUrl) return;
18057
- const filename = `${(title ?? "").replace(/[^a-z0-9]/gi, "-").toLowerCase()}.pdf`;
18058
- const href = `/api/download?url=${encodeURIComponent(pdfUrl)}&filename=${encodeURIComponent(filename)}`;
18059
- try {
18060
- const response = await fetch(href);
18061
- if (!response.ok) throw new Error(`status ${response.status}`);
18062
- const blob = await response.blob();
18063
- const objectUrl = window.URL.createObjectURL(blob);
18064
- const anchor = document.createElement("a");
18065
- anchor.href = objectUrl;
18066
- anchor.download = filename;
18067
- document.body.appendChild(anchor);
18068
- anchor.click();
18069
- anchor.remove();
18070
- window.URL.revokeObjectURL(objectUrl);
18071
- } catch {
18072
- window.open(pdfUrl, "_blank", "noopener,noreferrer");
18073
- }
18074
- };
18075
18175
  const resolveShareLink = () => {
18076
18176
  if (shareUrl) return shareUrl;
18077
18177
  if (typeof window !== "undefined" && job_id) {
@@ -18197,30 +18297,93 @@ var ResearchReportJobCard = (props) => {
18197
18297
  ),
18198
18298
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex-1 min-w-0", children: [
18199
18299
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title }),
18200
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("p", { className: "text-xs text-zinc-500 mt-0.5", children: [
18201
- depth && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "capitalize", children: depth }),
18202
- depth && sectionCount > 0 && " \xB7 ",
18203
- sectionCount > 0 && `${sectionCount} sections`,
18204
- sourceCount > 0 && ` \xB7 ${sourceCount} sources`,
18205
- wordCount > 0 && ` \xB7 ${formatWordCount(wordCount)} words`,
18206
- templateLabel && ` \xB7 ${templateLabel}`
18300
+ (depth || sectionCount > 0 || sourceCount > 0 || wordCount > 0 || templateLabel) && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5 mt-1.5", children: [
18301
+ depth && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(Chip2, { children: depth }),
18302
+ sectionCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(Chip2, { children: [
18303
+ sectionCount,
18304
+ " sections"
18305
+ ] }),
18306
+ sourceCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(Chip2, { children: [
18307
+ sourceCount,
18308
+ " sources"
18309
+ ] }),
18310
+ wordCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(Chip2, { children: [
18311
+ formatWordCount(wordCount),
18312
+ " words"
18313
+ ] }),
18314
+ templateLabel && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(Chip2, { children: templateLabel })
18207
18315
  ] }),
18208
- generationMode === "template" && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-emerald-400/90", children: "Approved \u2014 future reports use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-amber-400/90", children: "Review this report, then approve to lock the layout" }) : null })
18316
+ generationMode === "template" && (isApproved || reviewStatus === "pending_review") && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("p", { className: "flex items-center gap-1.5 text-xs mt-2", children: [
18317
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
18318
+ "span",
18319
+ {
18320
+ className: cn(
18321
+ "w-1.5 h-1.5 rounded-full flex-shrink-0",
18322
+ isApproved ? "bg-emerald-400" : "bg-amber-400"
18323
+ )
18324
+ }
18325
+ ),
18326
+ isApproved ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-emerald-400/90", children: "Approved \u2014 future reports use this format" }) : /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-amber-400/90", children: "Review this report, then approve to lock the layout" })
18327
+ ] })
18209
18328
  ] }),
18210
18329
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
18211
- canRegenerate && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18212
- "button",
18213
- {
18214
- onClick: handleRegenerate,
18215
- disabled: regenerating || approving,
18216
- title: "Try another report template with the same data",
18217
- className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-300 text-xs font-medium transition-colors disabled:opacity-50",
18218
- children: [
18219
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(RefreshIcon2, {}),
18220
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: regenerating ? "Switching..." : "Regenerate" })
18221
- ]
18222
- }
18223
- ),
18330
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center rounded-lg border border-zinc-700 bg-zinc-800 overflow-hidden divide-x divide-zinc-700", children: [
18331
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18332
+ "a",
18333
+ {
18334
+ href: htmlUrl ? `/reports/${job_id}/edit` : void 0,
18335
+ "aria-disabled": !htmlUrl,
18336
+ title: "Edit report content",
18337
+ className: cn(
18338
+ "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors",
18339
+ !htmlUrl && "pointer-events-none opacity-40"
18340
+ ),
18341
+ children: [
18342
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(EditIcon2, {}),
18343
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "Edit" })
18344
+ ]
18345
+ }
18346
+ ),
18347
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18348
+ "button",
18349
+ {
18350
+ onClick: () => setShowPreview(true),
18351
+ disabled: !hasHTML,
18352
+ title: "Preview report",
18353
+ className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
18354
+ children: [
18355
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ExpandIcon2, {}),
18356
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "Preview" })
18357
+ ]
18358
+ }
18359
+ ),
18360
+ canRegenerate && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18361
+ "button",
18362
+ {
18363
+ onClick: handleRegenerate,
18364
+ disabled: regenerating || approving,
18365
+ title: "Try another report template with the same data",
18366
+ className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60 transition-colors disabled:opacity-40",
18367
+ children: [
18368
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(RefreshIcon2, {}),
18369
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: regenerating ? "Switching\u2026" : "Regenerate" })
18370
+ ]
18371
+ }
18372
+ ),
18373
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
18374
+ "button",
18375
+ {
18376
+ onClick: handleShare,
18377
+ disabled: !canShare,
18378
+ title: !canShare && reviewStatus === "pending_review" ? "Approve the report to enable sharing" : copied ? "Copied!" : "Copy shareable link",
18379
+ className: cn(
18380
+ "flex items-center justify-center w-7 h-7 transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
18381
+ copied ? "text-green-400" : "text-zinc-300 hover:text-zinc-100 hover:bg-zinc-700/60"
18382
+ ),
18383
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}) : /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ShareIcon2, {})
18384
+ }
18385
+ )
18386
+ ] }),
18224
18387
  canApprove && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18225
18388
  "button",
18226
18389
  {
@@ -18235,53 +18398,15 @@ var ResearchReportJobCard = (props) => {
18235
18398
  }
18236
18399
  ),
18237
18400
  isApproved && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "flex items-center justify-center w-7 h-7 rounded-lg border border-emerald-500/40 bg-emerald-500/10 text-emerald-400", title: "Format saved", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}) }),
18238
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
18239
- "button",
18240
- {
18241
- onClick: handleShare,
18242
- disabled: !canShare,
18243
- title: !canShare && reviewStatus === "pending_review" ? "Approve the report to enable sharing" : copied ? "Copied!" : "Copy shareable link",
18244
- className: cn(
18245
- "w-7 h-7 rounded-lg border flex items-center justify-center transition-all",
18246
- copied ? "border-green-500/40 bg-green-500/10 text-green-400" : "border-zinc-700 bg-zinc-800 text-zinc-400 hover:border-zinc-500 hover:text-zinc-200",
18247
- "disabled:opacity-30 disabled:cursor-not-allowed"
18248
- ),
18249
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}) : /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ShareIcon2, {})
18250
- }
18251
- ),
18252
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18253
- "button",
18254
- {
18255
- onClick: () => setShowPreview(true),
18256
- disabled: !hasHTML,
18257
- title: "Preview report",
18258
- className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-400 hover:text-zinc-200 text-xs font-medium transition-colors disabled:opacity-30 disabled:cursor-not-allowed",
18259
- children: [
18260
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ExpandIcon2, {}),
18261
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "Preview" })
18262
- ]
18263
- }
18264
- ),
18265
- pdfUrl && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18266
- "button",
18267
- {
18268
- onClick: handleDownloadPdf,
18269
- title: "Download PDF",
18270
- className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-400 hover:text-zinc-200 text-xs font-medium transition-colors",
18271
- children: [
18272
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DownloadIcon2, {}),
18273
- /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: "PDF" })
18274
- ]
18275
- }
18276
- ),
18277
18401
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
18278
18402
  "button",
18279
18403
  {
18280
- onClick: handleDownload,
18281
- disabled: !hasHTML,
18282
- className: "flex items-center gap-1.5 px-2.5 h-7 text-xs font-medium rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
18283
- style: { backgroundColor: primaryColor, color: readableOn(primaryColor) },
18284
- onMouseEnter: (e) => e.currentTarget.style.filter = "brightness(1.15)",
18404
+ onClick: () => setShowExport(true),
18405
+ disabled: !hasHTML && !pdfUrl,
18406
+ title: "Download this report (PDF or HTML)",
18407
+ className: "flex items-center gap-1.5 px-3 h-7 text-xs font-semibold rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
18408
+ style: { backgroundImage: GOLD_GRADIENT, color: readableOn(primaryColor) },
18409
+ onMouseEnter: (e) => e.currentTarget.style.filter = "brightness(1.1)",
18285
18410
  onMouseLeave: (e) => e.currentTarget.style.filter = "brightness(1)",
18286
18411
  children: [
18287
18412
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(DownloadIcon2, {}),
@@ -18335,6 +18460,15 @@ var ResearchReportJobCard = (props) => {
18335
18460
  title,
18336
18461
  onClose: () => setShowPreview(false)
18337
18462
  }
18463
+ ),
18464
+ showExport && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
18465
+ ReportExportModal,
18466
+ {
18467
+ htmlUrl,
18468
+ pdfUrl,
18469
+ title,
18470
+ onClose: () => setShowExport(false)
18471
+ }
18338
18472
  )
18339
18473
  ] });
18340
18474
  };
@@ -18479,7 +18613,7 @@ var WebSearchJobCard = ({
18479
18613
  {
18480
18614
  className: "h-[3px]",
18481
18615
  style: {
18482
- background: "linear-gradient(90deg, #d97706, #f59e0b, #d97706)",
18616
+ backgroundImage: "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B, #C0AE82, #8B7D5E)",
18483
18617
  backgroundSize: "200% 100%",
18484
18618
  animation: "gradient-shift 2s ease-in-out infinite"
18485
18619
  }
@@ -18501,7 +18635,7 @@ var WebSearchJobCard = ({
18501
18635
  className: "h-full rounded-full transition-all duration-500 ease-out",
18502
18636
  style: {
18503
18637
  width: `${Math.max(pct, 2)}%`,
18504
- background: "linear-gradient(90deg, #d97706, #f59e0b)"
18638
+ backgroundImage: "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)"
18505
18639
  }
18506
18640
  }
18507
18641
  ) }),
@@ -18511,7 +18645,7 @@ var WebSearchJobCard = ({
18511
18645
  ] })
18512
18646
  ] }),
18513
18647
  /* @__PURE__ */ (0, import_jsx_runtime149.jsxs)("div", { className: "flex items-center gap-2", children: [
18514
- /* @__PURE__ */ (0, import_jsx_runtime149.jsx)("div", { className: "w-2 h-2 rounded-full bg-amber-500 animate-pulse flex-shrink-0" }),
18648
+ /* @__PURE__ */ (0, import_jsx_runtime149.jsx)("div", { className: "w-2 h-2 rounded-full bg-[#C0AE82] animate-pulse flex-shrink-0" }),
18515
18649
  /* @__PURE__ */ (0, import_jsx_runtime149.jsx)("span", { className: "text-xs text-zinc-400", children: step })
18516
18650
  ] }),
18517
18651
  searchesTotal > 0 && /* @__PURE__ */ (0, import_jsx_runtime149.jsxs)("div", { className: "pt-1", children: [
@@ -18528,7 +18662,7 @@ var WebSearchJobCard = ({
18528
18662
  {
18529
18663
  className: cn(
18530
18664
  "flex-1 h-1 rounded-full transition-all duration-300",
18531
- i < searchesCompleted ? "bg-amber-500" : phase === "ai_generation" && i === searchesCompleted ? "bg-amber-500/50 animate-pulse" : "bg-zinc-700"
18665
+ i < searchesCompleted ? "bg-[#C0AE82]" : phase === "ai_generation" && i === searchesCompleted ? "bg-[#C0AE82]/50 animate-pulse" : "bg-zinc-700"
18532
18666
  )
18533
18667
  },
18534
18668
  i
@@ -21768,7 +21902,7 @@ function PlatformMetricsBanner({
21768
21902
  return /* @__PURE__ */ (0, import_jsx_runtime173.jsxs)(
21769
21903
  "div",
21770
21904
  {
21771
- className: "\r\n grid grid-cols-1 gap-3 rounded-xl py-4 px-4 shadow-sm\r\n md:flex md:overflow-x-auto md:gap-6 md:rounded-l-xl md:py-4 md:px-4 md:items-center md:gap-0 md:px-0 md:ml-8\r\n ",
21905
+ className: "\n grid grid-cols-1 gap-3 rounded-xl py-4 px-4 shadow-sm\n md:flex md:overflow-x-auto md:gap-6 md:rounded-l-xl md:py-4 md:px-4 md:items-center md:gap-0 md:px-0 md:ml-8\n ",
21772
21906
  style: { backgroundColor: bgColor },
21773
21907
  children: [
21774
21908
  /* @__PURE__ */ (0, import_jsx_runtime173.jsxs)("div", { className: "flex flex-col items-center md:min-w-0", children: [