@primestyleai/tryon 5.10.193 → 5.10.195

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.
@@ -6981,7 +6981,7 @@ const es = {
6981
6981
  "See Your Fit": "Ver tu ajuste",
6982
6982
  "Check your size, then try it on virtually": "Comprueba tu talla y pruébatelo virtualmente",
6983
6983
  "Get Your Size": "Tu talla",
6984
- "Instant fit recommendation": "Recomendación de ajuste instantánea",
6984
+ "Instant fit suggestion": "Sugerencia de ajuste instantánea",
6985
6985
  "Try It On": "Pruébatelo",
6986
6986
  "See how it looks on you": "Mira cómo te queda",
6987
6987
  "Find My Size": "Encontrar mi talla",
@@ -7009,12 +7009,12 @@ const es = {
7009
7009
  "Please fill in all required fields": "Por favor, completa todos los campos obligatorios",
7010
7010
  "Next": "Siguiente",
7011
7011
  "Analyzing your size...": "Analizando tu talla...",
7012
- "RECOMMENDED SIZE": "TALLA RECOMENDADA",
7013
- "NOT RECOMMENDED": "NO RECOMENDADA",
7012
+ "SUGGESTED SIZE": "TALLA SUGERIDA",
7013
+ "NOT SUGGESTED": "NO SUGERIDA",
7014
7014
  "Edit measurements": "Editar medidas",
7015
7015
  "Size guide": "Guía de tallas",
7016
7016
  "Your fit": "Tu ajuste",
7017
- "Your Size Recommendation": "Tu recomendación de talla",
7017
+ "Your Suggested Size": "Tu talla sugerida",
7018
7018
  "Your measure": "Tu medida",
7019
7019
  "within range": "dentro del rango",
7020
7020
  "too tight": "demasiado ajustado",
@@ -7237,7 +7237,7 @@ const fr = {
7237
7237
  "See Your Fit": "Voir votre ajustement",
7238
7238
  "Check your size, then try it on virtually": "Vérifiez votre taille, puis essayez-le virtuellement",
7239
7239
  "Get Your Size": "Votre taille",
7240
- "Instant fit recommendation": "Recommandation de coupe instantanée",
7240
+ "Instant fit suggestion": "Suggestion de coupe instantanée",
7241
7241
  "Try It On": "Essayer",
7242
7242
  "See how it looks on you": "Voyez comment ça vous va",
7243
7243
  "Find My Size": "Trouver ma taille",
@@ -7265,12 +7265,12 @@ const fr = {
7265
7265
  "Please fill in all required fields": "Veuillez remplir tous les champs obligatoires",
7266
7266
  "Next": "Suivant",
7267
7267
  "Analyzing your size...": "Analyse de votre taille...",
7268
- "RECOMMENDED SIZE": "TAILLE RECOMMANDÉE",
7269
- "NOT RECOMMENDED": "NON RECOMMANDÉE",
7268
+ "SUGGESTED SIZE": "TAILLE SUGGÉRÉE",
7269
+ "NOT SUGGESTED": "NON SUGGÉRÉE",
7270
7270
  "Edit measurements": "Modifier les mesures",
7271
7271
  "Size guide": "Guide des tailles",
7272
7272
  "Your fit": "Votre coupe",
7273
- "Your Size Recommendation": "Votre recommandation de taille",
7273
+ "Your Suggested Size": "Votre taille suggérée",
7274
7274
  "Your measure": "Votre mesure",
7275
7275
  "within range": "dans la plage",
7276
7276
  "too tight": "trop serré",
@@ -7493,7 +7493,7 @@ const de = {
7493
7493
  "See Your Fit": "Ihre Passform ansehen",
7494
7494
  "Check your size, then try it on virtually": "Prüfen Sie Ihre Größe und probieren Sie es virtuell an",
7495
7495
  "Get Your Size": "Ihre Größe",
7496
- "Instant fit recommendation": "Sofortige Passformempfehlung",
7496
+ "Instant fit suggestion": "Sofortiger Passformvorschlag",
7497
7497
  "Try It On": "Anprobieren",
7498
7498
  "See how it looks on you": "Sehen Sie, wie es Ihnen steht",
7499
7499
  "Find My Size": "Meine Größe finden",
@@ -7521,12 +7521,12 @@ const de = {
7521
7521
  "Please fill in all required fields": "Bitte alle Pflichtfelder ausfüllen",
7522
7522
  "Next": "Weiter",
7523
7523
  "Analyzing your size...": "Ihre Größe wird analysiert...",
7524
- "RECOMMENDED SIZE": "EMPFOHLENE GRÖSSE",
7525
- "NOT RECOMMENDED": "NICHT EMPFOHLEN",
7524
+ "SUGGESTED SIZE": "VORGESCHLAGENE GRÖSSE",
7525
+ "NOT SUGGESTED": "NICHT VORGESCHLAGEN",
7526
7526
  "Edit measurements": "Maße bearbeiten",
7527
7527
  "Size guide": "Größentabelle",
7528
7528
  "Your fit": "Ihre Passform",
7529
- "Your Size Recommendation": "Ihre Größenempfehlung",
7529
+ "Your Suggested Size": "Ihre vorgeschlagene Größe",
7530
7530
  "Your measure": "Ihr Maß",
7531
7531
  "within range": "im Bereich",
7532
7532
  "too tight": "zu eng",
@@ -7749,7 +7749,7 @@ const it = {
7749
7749
  "See Your Fit": "Vedi la vestibilità",
7750
7750
  "Check your size, then try it on virtually": "Controlla la tua taglia, poi provalo virtualmente",
7751
7751
  "Get Your Size": "La tua taglia",
7752
- "Instant fit recommendation": "Raccomandazione vestibilità istantanea",
7752
+ "Instant fit suggestion": "Suggerimento vestibilità istantaneo",
7753
7753
  "Try It On": "Provalo",
7754
7754
  "See how it looks on you": "Guarda come ti sta",
7755
7755
  "Find My Size": "Trova la mia taglia",
@@ -7777,12 +7777,12 @@ const it = {
7777
7777
  "Please fill in all required fields": "Compila tutti i campi obbligatori",
7778
7778
  "Next": "Avanti",
7779
7779
  "Analyzing your size...": "Analisi della tua taglia...",
7780
- "RECOMMENDED SIZE": "TAGLIA CONSIGLIATA",
7781
- "NOT RECOMMENDED": "NON CONSIGLIATA",
7780
+ "SUGGESTED SIZE": "TAGLIA SUGGERITA",
7781
+ "NOT SUGGESTED": "NON SUGGERITA",
7782
7782
  "Edit measurements": "Modifica misure",
7783
7783
  "Size guide": "Guida alle taglie",
7784
7784
  "Your fit": "La tua vestibilità",
7785
- "Your Size Recommendation": "La tua taglia consigliata",
7785
+ "Your Suggested Size": "La tua taglia suggerita",
7786
7786
  "Your measure": "La tua misura",
7787
7787
  "within range": "entro l'intervallo",
7788
7788
  "too tight": "troppo stretto",
@@ -8005,7 +8005,7 @@ const pt$1 = {
8005
8005
  "See Your Fit": "Veja seu ajuste",
8006
8006
  "Check your size, then try it on virtually": "Confira seu tamanho e experimente virtualmente",
8007
8007
  "Get Your Size": "Seu tamanho",
8008
- "Instant fit recommendation": "Recomendação de caimento instantânea",
8008
+ "Instant fit suggestion": "Sugestão de caimento instantânea",
8009
8009
  "Try It On": "Experimentar",
8010
8010
  "See how it looks on you": "Veja como fica em você",
8011
8011
  "Find My Size": "Encontrar meu tamanho",
@@ -8033,12 +8033,12 @@ const pt$1 = {
8033
8033
  "Please fill in all required fields": "Por favor, preencha todos os campos obrigatórios",
8034
8034
  "Next": "Próximo",
8035
8035
  "Analyzing your size...": "Analisando seu tamanho...",
8036
- "RECOMMENDED SIZE": "TAMANHO RECOMENDADO",
8037
- "NOT RECOMMENDED": "NÃO RECOMENDADO",
8036
+ "SUGGESTED SIZE": "TAMANHO SUGERIDO",
8037
+ "NOT SUGGESTED": "NÃO SUGERIDO",
8038
8038
  "Edit measurements": "Editar medidas",
8039
8039
  "Size guide": "Guia de tamanhos",
8040
8040
  "Your fit": "Seu caimento",
8041
- "Your Size Recommendation": "Sua recomendação de tamanho",
8041
+ "Your Suggested Size": "Seu tamanho sugerido",
8042
8042
  "Your measure": "Sua medida",
8043
8043
  "within range": "dentro da faixa",
8044
8044
  "too tight": "muito apertado",
@@ -8261,7 +8261,7 @@ const ja = {
8261
8261
  "See Your Fit": "フィット感を見る",
8262
8262
  "Check your size, then try it on virtually": "サイズを確認して、バーチャルで試着しましょう",
8263
8263
  "Get Your Size": "サイズを確認",
8264
- "Instant fit recommendation": "瞬時にフィット提案",
8264
+ "Instant fit suggestion": "瞬時にフィット提案",
8265
8265
  "Try It On": "試着する",
8266
8266
  "See how it looks on you": "自分に似合うか確認",
8267
8267
  "Find My Size": "自分のサイズを見つける",
@@ -8289,12 +8289,12 @@ const ja = {
8289
8289
  "Please fill in all required fields": "すべての必須項目を入力してください",
8290
8290
  "Next": "次へ",
8291
8291
  "Analyzing your size...": "サイズを分析中...",
8292
- "RECOMMENDED SIZE": "推奨サイズ",
8293
- "NOT RECOMMENDED": "非推奨",
8292
+ "SUGGESTED SIZE": "提案サイズ",
8293
+ "NOT SUGGESTED": "提案外",
8294
8294
  "Edit measurements": "寸法を編集",
8295
8295
  "Size guide": "サイズガイド",
8296
8296
  "Your fit": "あなたのフィット",
8297
- "Your Size Recommendation": "サイズのおすすめ",
8297
+ "Your Suggested Size": "提案サイズ",
8298
8298
  "Your measure": "あなたの寸法",
8299
8299
  "within range": "範囲内",
8300
8300
  "too tight": "きつすぎる",
@@ -8517,7 +8517,7 @@ const zh = {
8517
8517
  "See Your Fit": "查看合身效果",
8518
8518
  "Check your size, then try it on virtually": "确认尺码,然后虚拟试穿",
8519
8519
  "Get Your Size": "获取尺码",
8520
- "Instant fit recommendation": "即时合身推荐",
8520
+ "Instant fit suggestion": "即时合身建议",
8521
8521
  "Try It On": "试穿",
8522
8522
  "See how it looks on you": "看看穿在你身上的效果",
8523
8523
  "Find My Size": "找到我的尺码",
@@ -8545,12 +8545,12 @@ const zh = {
8545
8545
  "Please fill in all required fields": "请填写所有必填项",
8546
8546
  "Next": "下一步",
8547
8547
  "Analyzing your size...": "正在分析你的尺码...",
8548
- "RECOMMENDED SIZE": "推荐尺码",
8549
- "NOT RECOMMENDED": "不推荐",
8548
+ "SUGGESTED SIZE": "建议尺码",
8549
+ "NOT SUGGESTED": "不建议",
8550
8550
  "Edit measurements": "编辑尺寸",
8551
8551
  "Size guide": "尺码指南",
8552
8552
  "Your fit": "你的合身度",
8553
- "Your Size Recommendation": "你的尺码建议",
8553
+ "Your Suggested Size": "你的建议尺码",
8554
8554
  "Your measure": "你的尺寸",
8555
8555
  "within range": "在范围内",
8556
8556
  "too tight": "太紧",
@@ -8773,7 +8773,7 @@ const ko = {
8773
8773
  "See Your Fit": "핏 확인하기",
8774
8774
  "Check your size, then try it on virtually": "사이즈를 확인하고 가상으로 입어보세요",
8775
8775
  "Get Your Size": "사이즈 확인",
8776
- "Instant fit recommendation": "즉시 핏 추천",
8776
+ "Instant fit suggestion": "즉시 핏 제안",
8777
8777
  "Try It On": "입어보기",
8778
8778
  "See how it looks on you": "어떻게 보이는지 확인",
8779
8779
  "Find My Size": "내 사이즈 찾기",
@@ -8801,12 +8801,12 @@ const ko = {
8801
8801
  "Please fill in all required fields": "모든 필수 항목을 입력해주세요",
8802
8802
  "Next": "다음",
8803
8803
  "Analyzing your size...": "사이즈 분석 중...",
8804
- "RECOMMENDED SIZE": "추천 사이즈",
8805
- "NOT RECOMMENDED": "비추천",
8804
+ "SUGGESTED SIZE": "제안 사이즈",
8805
+ "NOT SUGGESTED": "제안 아님",
8806
8806
  "Edit measurements": "치수 수정",
8807
8807
  "Size guide": "사이즈 가이드",
8808
8808
  "Your fit": "나의 핏",
8809
- "Your Size Recommendation": "사이즈 추천",
8809
+ "Your Suggested Size": "제안 사이즈",
8810
8810
  "Your measure": "내 치수",
8811
8811
  "within range": "범위 내",
8812
8812
  "too tight": "너무 타이트",
@@ -9029,7 +9029,7 @@ const ar = {
9029
9029
  "See Your Fit": "شاهد الملاءمة",
9030
9030
  "Check your size, then try it on virtually": "تحقق من مقاسك ثم جرّبه افتراضياً",
9031
9031
  "Get Your Size": "مقاسك",
9032
- "Instant fit recommendation": "توصية فورية بالمقاس",
9032
+ "Instant fit suggestion": "اقتراح فوري للمقاس",
9033
9033
  "Try It On": "جرّبه",
9034
9034
  "See how it looks on you": "شاهد كيف يبدو عليك",
9035
9035
  "Find My Size": "اعثر على مقاسي",
@@ -9057,12 +9057,12 @@ const ar = {
9057
9057
  "Please fill in all required fields": "يرجى ملء جميع الحقول المطلوبة",
9058
9058
  "Next": "التالي",
9059
9059
  "Analyzing your size...": "جارٍ تحليل مقاسك...",
9060
- "RECOMMENDED SIZE": "المقاس الموصى به",
9061
- "NOT RECOMMENDED": "غير موصى به",
9060
+ "SUGGESTED SIZE": "المقاس المقترح",
9061
+ "NOT SUGGESTED": "غير مقترح",
9062
9062
  "Edit measurements": "تعديل القياسات",
9063
9063
  "Size guide": "دليل المقاسات",
9064
9064
  "Your fit": "ملاءمتك",
9065
- "Your Size Recommendation": "توصية المقاس",
9065
+ "Your Suggested Size": "المقاس المقترح",
9066
9066
  "Your measure": "قياسك",
9067
9067
  "within range": "ضمن النطاق",
9068
9068
  "too tight": "ضيق جداً",
@@ -9321,53 +9321,6 @@ reactJsxRuntime_production_min.jsxs = q;
9321
9321
  jsxRuntime.exports = reactJsxRuntime_production_min;
9322
9322
  }
9323
9323
  var jsxRuntimeExports = jsxRuntime.exports;
9324
- function cx(base, override) {
9325
- return override ? `${base} ${override}` : base;
9326
- }
9327
- const MOBILE_BREAKPOINT = 768;
9328
- function useIsMobile() {
9329
- const [isMobile, setIsMobile] = reactExports.useState(false);
9330
- reactExports.useEffect(() => {
9331
- if (typeof window === "undefined") return;
9332
- const check = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
9333
- check();
9334
- window.addEventListener("resize", check);
9335
- return () => window.removeEventListener("resize", check);
9336
- }, []);
9337
- return isMobile;
9338
- }
9339
- function ErrorView({
9340
- productImage,
9341
- productTitle,
9342
- onManualMeasurements,
9343
- cn,
9344
- t: t2
9345
- }) {
9346
- const isMobile = useIsMobile();
9347
- const RightColumn = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cx("ps-tryon-no-chart-content ps-tryon-error-fallback", cn.error), children: [
9348
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-icon ps-tryon-error-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "44", height: "44", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
9349
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3l8.5 15H3.5L12 3z" }),
9350
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 9v4" }),
9351
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 17h.01" })
9352
- ] }) }),
9353
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: t2("We couldn't find a matching size for you") }),
9354
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cx("ps-tryon-no-chart-msg", cn.errorText), children: t2("Please try the manual measurement screen so we can calculate your fit from your measurements.") }),
9355
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", onClick: onManualMeasurements, className: cx("ps-tryon-no-chart-cta", cn.submitButton), children: [
9356
- t2("Try manual measurements"),
9357
- " →"
9358
- ] }) })
9359
- ] });
9360
- if (isMobile) {
9361
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr", children: [
9362
- productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", style: { flex: "0 0 auto", maxHeight: "38vh" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
9363
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-right-col", children: RightColumn })
9364
- ] });
9365
- }
9366
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-split", children: [
9367
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", children: productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
9368
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col ps-tryon-no-chart-right-col", children: RightColumn })
9369
- ] }) });
9370
- }
9371
9324
  const STORAGE_KEY = "ps_session";
9372
9325
  const MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
9373
9326
  const FALLBACK_PREFIX = "ps_mem_";
@@ -9412,6 +9365,14 @@ function writeRecord(record) {
9412
9365
  } catch {
9413
9366
  }
9414
9367
  }
9368
+ function attachReplaySession(sessionId) {
9369
+ if (typeof window === "undefined") return;
9370
+ try {
9371
+ const clarity = window.clarity;
9372
+ if (typeof clarity === "function") clarity("set", STORAGE_KEY, sessionId);
9373
+ } catch {
9374
+ }
9375
+ }
9415
9376
  function getOrCreateSessionId() {
9416
9377
  const now = Date.now();
9417
9378
  const existing = readRecord();
@@ -9419,10 +9380,12 @@ function getOrCreateSessionId() {
9419
9380
  if (now - existing.lastSeenAt > 5 * 60 * 1e3) {
9420
9381
  writeRecord({ ...existing, lastSeenAt: now });
9421
9382
  }
9383
+ attachReplaySession(existing.id);
9422
9384
  return existing.id;
9423
9385
  }
9424
9386
  const fresh = { id: uuid(), issuedAt: now, lastSeenAt: now };
9425
9387
  writeRecord(fresh);
9388
+ attachReplaySession(fresh.id);
9426
9389
  return fresh.id;
9427
9390
  }
9428
9391
  function getDeviceHint() {
@@ -9544,8 +9507,49 @@ class ApiClient {
9544
9507
  }
9545
9508
  return res.json();
9546
9509
  }
9547
- getStreamUrl() {
9548
- const streamUrl = `${this.baseUrl}/api/v1/tryon/stream`;
9510
+ async reportEvent(input) {
9511
+ const res = await fetch(`${this.baseUrl}/api/v1/tryon/event`, {
9512
+ method: "POST",
9513
+ headers: this.headers,
9514
+ keepalive: true,
9515
+ body: JSON.stringify({
9516
+ ...input,
9517
+ sessionId: getOrCreateSessionId(),
9518
+ deviceHint: getDeviceHint()
9519
+ })
9520
+ });
9521
+ if (!res.ok) {
9522
+ const data = await res.json().catch(() => ({}));
9523
+ throw new PrimeStyleError(
9524
+ data.message || "Failed to report SDK event",
9525
+ "EVENT_REPORT_FAILED"
9526
+ );
9527
+ }
9528
+ return res.json();
9529
+ }
9530
+ async reportClientError(input) {
9531
+ const res = await fetch(`${this.baseUrl}/api/v1/tryon/client-error`, {
9532
+ method: "POST",
9533
+ headers: this.headers,
9534
+ keepalive: true,
9535
+ body: JSON.stringify({
9536
+ ...input,
9537
+ sessionId: getOrCreateSessionId(),
9538
+ deviceHint: getDeviceHint()
9539
+ })
9540
+ });
9541
+ if (!res.ok) {
9542
+ const data = await res.json().catch(() => ({}));
9543
+ throw new PrimeStyleError(
9544
+ data.message || "Failed to report SDK client error",
9545
+ "CLIENT_ERROR_REPORT_FAILED"
9546
+ );
9547
+ }
9548
+ return res.json();
9549
+ }
9550
+ getStreamUrl(jobId) {
9551
+ const streamPath = jobId ? `/api/v1/tryon/stream/${encodeURIComponent(jobId)}` : "/api/v1/tryon/stream";
9552
+ const streamUrl = `${this.baseUrl}${streamPath}`;
9549
9553
  return this.apiKey ? `${streamUrl}?key=${encodeURIComponent(this.apiKey)}` : streamUrl;
9550
9554
  }
9551
9555
  }
@@ -9561,6 +9565,89 @@ class PrimeStyleError extends Error {
9561
9565
  this.code = code;
9562
9566
  }
9563
9567
  }
9568
+ function detectLocale() {
9569
+ if (typeof navigator === "undefined") return "US";
9570
+ const lang = navigator.language || "";
9571
+ const region = lang.split("-")[1]?.toUpperCase();
9572
+ if (region === "GB") return "UK";
9573
+ if (region) return region;
9574
+ const map = {
9575
+ en: "US",
9576
+ ja: "JP",
9577
+ ko: "KR",
9578
+ zh: "CN",
9579
+ fr: "FR",
9580
+ it: "IT",
9581
+ de: "DE",
9582
+ es: "ES",
9583
+ pt: "BR"
9584
+ };
9585
+ return map[lang.split("-")[0].toLowerCase()] || "US";
9586
+ }
9587
+ function getApiKey() {
9588
+ let key = "";
9589
+ try {
9590
+ key = "shopify-proxy";
9591
+ } catch {
9592
+ }
9593
+ return key;
9594
+ }
9595
+ function getApiUrl(override) {
9596
+ if (override) return override;
9597
+ let envUrl = "";
9598
+ try {
9599
+ envUrl = "";
9600
+ } catch {
9601
+ }
9602
+ return envUrl || "http://localhost:4000";
9603
+ }
9604
+ function cx(base, override) {
9605
+ return override ? `${base} ${override}` : base;
9606
+ }
9607
+ const MOBILE_BREAKPOINT = 768;
9608
+ function useIsMobile() {
9609
+ const [isMobile, setIsMobile] = reactExports.useState(false);
9610
+ reactExports.useEffect(() => {
9611
+ if (typeof window === "undefined") return;
9612
+ const check = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
9613
+ check();
9614
+ window.addEventListener("resize", check);
9615
+ return () => window.removeEventListener("resize", check);
9616
+ }, []);
9617
+ return isMobile;
9618
+ }
9619
+ function ErrorView({
9620
+ productImage,
9621
+ productTitle,
9622
+ onManualMeasurements,
9623
+ cn,
9624
+ t: t2
9625
+ }) {
9626
+ const isMobile = useIsMobile();
9627
+ const RightColumn = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cx("ps-tryon-no-chart-content ps-tryon-error-fallback", cn.error), children: [
9628
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-icon ps-tryon-error-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "44", height: "44", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
9629
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3l8.5 15H3.5L12 3z" }),
9630
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 9v4" }),
9631
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 17h.01" })
9632
+ ] }) }),
9633
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: t2("We couldn't find a matching size for you") }),
9634
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cx("ps-tryon-no-chart-msg", cn.errorText), children: t2("Please try the manual measurement screen so we can calculate your fit from your measurements.") }),
9635
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", onClick: onManualMeasurements, className: cx("ps-tryon-no-chart-cta", cn.submitButton), children: [
9636
+ t2("Try manual measurements"),
9637
+ " →"
9638
+ ] }) })
9639
+ ] });
9640
+ if (isMobile) {
9641
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr", children: [
9642
+ productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", style: { flex: "0 0 auto", maxHeight: "38vh" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
9643
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-right-col", children: RightColumn })
9644
+ ] });
9645
+ }
9646
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-split", children: [
9647
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", children: productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
9648
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col ps-tryon-no-chart-right-col", children: RightColumn })
9649
+ ] }) });
9650
+ }
9564
9651
  class SseClient {
9565
9652
  constructor(streamUrl) {
9566
9653
  this.eventSource = null;
@@ -10932,42 +11019,6 @@ function installCartHook() {
10932
11019
  }
10933
11020
  console.log(TAG$1, "attribution hook installed");
10934
11021
  }
10935
- function detectLocale() {
10936
- if (typeof navigator === "undefined") return "US";
10937
- const lang = navigator.language || "";
10938
- const region = lang.split("-")[1]?.toUpperCase();
10939
- if (region === "GB") return "UK";
10940
- if (region) return region;
10941
- const map = {
10942
- en: "US",
10943
- ja: "JP",
10944
- ko: "KR",
10945
- zh: "CN",
10946
- fr: "FR",
10947
- it: "IT",
10948
- de: "DE",
10949
- es: "ES",
10950
- pt: "BR"
10951
- };
10952
- return map[lang.split("-")[0].toLowerCase()] || "US";
10953
- }
10954
- function getApiKey() {
10955
- let key = "";
10956
- try {
10957
- key = "shopify-proxy";
10958
- } catch {
10959
- }
10960
- return key;
10961
- }
10962
- function getApiUrl(override) {
10963
- if (override) return override;
10964
- let envUrl = "";
10965
- try {
10966
- envUrl = "";
10967
- } catch {
10968
- }
10969
- return envUrl || "http://localhost:4000";
10970
- }
10971
11022
  const SESSION_KEY = "primestyle_profile_session";
10972
11023
  const AUTH_MESSAGE_TYPE = "PRIMESTYLE_SDK_AUTH";
10973
11024
  const POPUP_TIMEOUT_MS = 12e4;
@@ -11150,6 +11201,30 @@ async function saveRemoteProfiles(apiUrl, accessToken, profiles, activeProfileId
11150
11201
  });
11151
11202
  return normalizeStore(await parseResponse(response));
11152
11203
  }
11204
+ function shouldUseShopifyProxy(apiUrl) {
11205
+ if (typeof window === "undefined") return false;
11206
+ try {
11207
+ const w2 = window;
11208
+ if (w2.Shopify?.shop) return true;
11209
+ return /\/apps\/primestyle\/?$/.test(apiUrl);
11210
+ } catch {
11211
+ return false;
11212
+ }
11213
+ }
11214
+ function reportDirectSdkEvent(apiUrl, apiKey, body) {
11215
+ if (!apiKey || shouldUseShopifyProxy(apiUrl)) return;
11216
+ void fetch(`${apiUrl}/api/v1/tryon/event`, {
11217
+ method: "POST",
11218
+ headers: jsonHeaders(apiKey),
11219
+ keepalive: true,
11220
+ body: JSON.stringify({
11221
+ ...body,
11222
+ sessionId: getOrCreateSessionId(),
11223
+ deviceHint: getDeviceHint()
11224
+ })
11225
+ }).catch(() => {
11226
+ });
11227
+ }
11153
11228
  let cachedMP = null;
11154
11229
  const MP_CACHE_TTL_MS = 6e4;
11155
11230
  function setCachedMediaPipe(landmarks) {
@@ -11223,6 +11298,13 @@ async function recommendForProduct(input) {
11223
11298
  recommendedSize: cached.recommendedSize,
11224
11299
  fromCache: true
11225
11300
  });
11301
+ reportDirectSdkEvent(apiUrl, apiKey, {
11302
+ eventType: "SIZE_RECOMMENDATION_SHOWN",
11303
+ productId: input.productId,
11304
+ productTitle: input.productTitle,
11305
+ recommendedSize: cached.recommendedSize,
11306
+ metadata: { fromCache: true, profileId: profile.id }
11307
+ });
11226
11308
  const reconstructedRaw = cached.sectionsFull ? {
11227
11309
  recommendedSize: cached.recommendedSize,
11228
11310
  confidence: cached.confidence || "high",
@@ -11434,6 +11516,19 @@ async function recommendForProduct(input) {
11434
11516
  size: result.recommendedSize,
11435
11517
  recommendedSize: result.recommendedSize
11436
11518
  });
11519
+ logSizeShown({
11520
+ productId: input.productId,
11521
+ productTitle: input.productTitle,
11522
+ recommendedSize: result.recommendedSize,
11523
+ fromCache: false
11524
+ });
11525
+ reportDirectSdkEvent(apiUrl, apiKey, {
11526
+ eventType: "SIZE_RECOMMENDATION_SHOWN",
11527
+ productId: input.productId,
11528
+ productTitle: input.productTitle,
11529
+ recommendedSize: result.recommendedSize,
11530
+ metadata: { fromCache: false, profileId: profile.id, found: result.found }
11531
+ });
11437
11532
  return {
11438
11533
  recommendedSize: result.recommendedSize,
11439
11534
  confidence: result.confidence,
@@ -11785,7 +11880,8 @@ function productFitTypeToMeasurementType(fitType) {
11785
11880
  if (fitType === "shoe") return "foot";
11786
11881
  if (fitType === "hat") return "head";
11787
11882
  if (fitType === "sunglasses") return "face";
11788
- if (fitType === "bracelet" || fitType === "watch") return "wrist";
11883
+ if (fitType === "watch") return "wrist";
11884
+ if (fitType === "bracelet") return "body-basic";
11789
11885
  if (fitType === "bag" || fitType === "belt" || fitType === "earring" || fitType === "necklace" || fitType === "ring" || fitType === "accessory") {
11790
11886
  return "body-basic";
11791
11887
  }
@@ -12344,6 +12440,9 @@ const STYLES = `
12344
12440
  .ps-tryon-v2-result-panel .ps-tryon-v2-sep {
12345
12441
  margin-bottom: 0;
12346
12442
  }
12443
+ .ps-tryon-v2-multi-result-panel .ps-tryon-v2-result-copy {
12444
+ flex: 0 0 auto;
12445
+ }
12347
12446
  .ps-tryon-v2-result-panel .ps-tryon-sr-cards-v2 {
12348
12447
  flex: 0 0 auto;
12349
12448
  min-height: 0;
@@ -14690,6 +14789,34 @@ const STYLES = `
14690
14789
  .ps-tryon-sec-detail .ps-tryon-sr-fit-table td { padding: 0.9vw 0; }
14691
14790
  .ps-tryon-sec-detail .ps-tryon-sr-fit-table th { padding: 0.4vw 0 0.6vw; }
14692
14791
  .ps-tryon-sec-detail .ps-tryon-sr-chips { gap: 0.4vw; margin: 0.3vw 0; }
14792
+ .ps-tryon-sec-detail-footer {
14793
+ gap: clamp(16px, 1.1vw, 22px);
14794
+ min-height: clamp(44px, 3vw, 54px);
14795
+ }
14796
+ .ps-tryon-sec-detail-footer .ps-bp-back-btn {
14797
+ flex: 0 0 auto;
14798
+ min-width: 0;
14799
+ white-space: nowrap;
14800
+ }
14801
+ .ps-tryon-sec-detail-footer .ps-tryon-v2-action-group {
14802
+ flex: 1 1 auto;
14803
+ max-width: min(430px, 100%);
14804
+ margin-left: auto;
14805
+ gap: clamp(16px, 1vw, 20px);
14806
+ }
14807
+ .ps-tryon-sec-detail-footer .ps-tryon-v2-action-group-single {
14808
+ flex: 0 0 auto;
14809
+ max-width: none;
14810
+ }
14811
+ .ps-tryon-sec-detail-footer .ps-tryon-v2-action-group > .ps-tryon-v2-cta {
14812
+ flex: 1 1 0;
14813
+ min-width: clamp(140px, 9.5vw, 178px);
14814
+ margin-top: 0;
14815
+ }
14816
+ .ps-tryon-sec-detail-footer .ps-tryon-v2-action-group-single > .ps-tryon-v2-cta {
14817
+ flex: 0 0 auto;
14818
+ min-width: clamp(150px, 10vw, 190px);
14819
+ }
14693
14820
 
14694
14821
  /* Length inline selector (inside section detail) */
14695
14822
  .ps-tryon-sec-length-row {
@@ -15018,7 +15145,7 @@ const STYLES = `
15018
15145
  transform: translateY(-1px);
15019
15146
  }
15020
15147
 
15021
- /* Size chip recommended dot */
15148
+ /* Size chip suggested dot */
15022
15149
  .ps-tryon-sr-chip { position: relative; }
15023
15150
  .ps-tryon-sr-rec-dot {
15024
15151
  position: absolute; bottom: -0.3vw; left: 50%; transform: translateX(-50%);
@@ -17064,6 +17191,13 @@ const STYLES = `
17064
17191
  font-size: clamp(11px, 0.66vw, 13px);
17065
17192
  padding: 0 0 3px;
17066
17193
  }
17194
+ .ps-bp-system-toggle-large {
17195
+ gap: clamp(18px, 1.1vw, 24px);
17196
+ }
17197
+ .ps-bp-system-toggle-large .ps-bp-system-btn {
17198
+ font-size: clamp(13px, 0.78vw, 15px);
17199
+ padding-bottom: 4px;
17200
+ }
17067
17201
 
17068
17202
  .ps-bp-root {
17069
17203
  flex: 1; min-width: 0;
@@ -20869,7 +21003,7 @@ const STYLES = `
20869
21003
  min-width: 0;
20870
21004
  }
20871
21005
 
20872
- /* RECOMMENDED SIZE card */
21006
+ /* SUGGESTED SIZE card */
20873
21007
  .ps-msd-card {
20874
21008
  background: var(--ps-bg-primary);
20875
21009
  border: 1px solid var(--ps-border-subtle);
@@ -21135,20 +21269,23 @@ const STYLES = `
21135
21269
  .ps-bp-photo-help-backdrop { display: none; }
21136
21270
  .ps-bp-photo-help {
21137
21271
  position: absolute; top: 2.2vw; right: 0;
21138
- width: min(360px, 22vw);
21272
+ width: min(520px, 34vw);
21139
21273
  background: #FFFFFF;
21140
21274
  border: 1px solid var(--ps-border-subtle);
21141
21275
  border-radius: 0.8vw;
21142
21276
  box-shadow: 0 20px 40px -12px rgba(17,24,39,0.25), 0 8px 16px -8px rgba(17,24,39,0.15);
21143
21277
  padding: 0.8vw 1vw;
21144
21278
  display: flex; flex-direction: column; gap: 0.6vw;
21279
+ max-height: min(70dvh, 520px);
21280
+ overflow-y: auto;
21281
+ -webkit-overflow-scrolling: touch;
21145
21282
  z-index: 5;
21146
21283
  }
21147
21284
  .ps-bp-photo-help-upload {
21148
21285
  top: clamp(46px, 3.2vw, 58px);
21149
21286
  left: clamp(12px, 0.85vw, 16px);
21150
21287
  right: auto;
21151
- width: min(360px, calc(100% - clamp(24px, 1.7vw, 32px)));
21288
+ width: min(620px, calc(100% - clamp(24px, 1.7vw, 32px)));
21152
21289
  max-height: calc(100% - clamp(64px, 4.5vw, 82px));
21153
21290
  overflow-y: auto;
21154
21291
  }
@@ -23672,7 +23809,7 @@ function WelcomeView({
23672
23809
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-welcome-sub", children: t2("Check your size, then try it on virtually") })
23673
23810
  ] }),
23674
23811
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-features", children: [
23675
- { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(RulerIcon$1, { size: 22 }), title: t2("Get Your Size"), desc: t2("Instant fit recommendation") },
23812
+ { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(RulerIcon$1, { size: 22 }), title: t2("Get Your Size"), desc: t2("Instant fit suggestion") },
23676
23813
  { icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, { size: 22 }), title: t2("Try It On"), desc: t2("See how it looks on you") }
23677
23814
  ].map((f2, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-feature", children: [
23678
23815
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-feature-icon", children: f2.icon }),
@@ -23991,24 +24128,24 @@ function MobileScanningView({
23991
24128
  { title: t2("DETECTING HEAD"), desc: t2("Reading head landmarks from your photo."), viewfinderText: t2("DETECTING HEAD") },
23992
24129
  { title: t2("MAPPING CIRCUMFERENCE"), desc: t2("Estimating head width and depth."), viewfinderText: t2("MAPPING") },
23993
24130
  { title: t2("MATCHING HAT SIZE"), desc: t2("Comparing your circumference to the size chart."), viewfinderText: t2("MATCHING SIZE") },
23994
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
24131
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size."), viewfinderText: t2("FINALIZING") }
23995
24132
  ] : [
23996
24133
  { title: t2("DETECTING FACE"), desc: t2("Identifying face landmarks in your photo."), viewfinderText: t2("DETECTING FACE") },
23997
24134
  { title: t2("CALIBRATING SCALE"), desc: t2("Using iris size as the pixel-to-mm anchor."), viewfinderText: t2("CALIBRATING") },
23998
24135
  { title: t2("MEASURING FRAME"), desc: t2("Mapping bridge, frame width and temple fit."), viewfinderText: t2("MEASURING") },
23999
24136
  { title: t2("MATCHING FRAME SIZE"), desc: t2("Comparing your measurements to the size chart."), viewfinderText: t2("MATCHING SIZE") },
24000
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
24137
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size."), viewfinderText: t2("FINALIZING") }
24001
24138
  ] : [
24002
24139
  { title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo."), viewfinderText: t2("DETECTING POSE") },
24003
- { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size recommendation."), viewfinderText: t2("SCANNING FRAME") },
24140
+ { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size suggestion."), viewfinderText: t2("SCANNING FRAME") },
24004
24141
  { title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips."), viewfinderText: t2("ANALYZING") },
24005
24142
  { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide."), viewfinderText: t2("MATCHING SIZE") },
24006
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
24143
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size."), viewfinderText: t2("FINALIZING") }
24007
24144
  ] : [
24008
24145
  { title: t2("READING YOUR PROFILE"), desc: t2("Loading your saved measurements and body shape answers."), viewfinderText: t2("READING PROFILE") },
24009
24146
  { title: t2("ESTIMATING BODY"), desc: t2("Computing chest, waist, hips, sleeve and inseam from your basics."), viewfinderText: t2("ESTIMATING BODY") },
24010
24147
  { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the garment's size guide."), viewfinderText: t2("MATCHING SIZE") },
24011
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
24148
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size."), viewfinderText: t2("FINALIZING") }
24012
24149
  ];
24013
24150
  const [dims, setDims] = reactExports.useState({ w: 800, h: 1200 });
24014
24151
  const handleImgLoad = (e) => {
@@ -24236,7 +24373,7 @@ function MultiSectionMobile({
24236
24373
  marginTop: "4px",
24237
24374
  color: isOverridden ? "#b45309" : "var(--ps-text-secondary, #6b7280)"
24238
24375
  },
24239
- children: isOverridden ? t2("your selection · not recommended") : t2("recommended")
24376
+ children: isOverridden ? t2("your selection · not suggested") : t2("suggested")
24240
24377
  }
24241
24378
  )
24242
24379
  ]
@@ -24735,13 +24872,13 @@ function StageCycler({
24735
24872
  { title: t2("DETECTING HEAD"), desc: t2("Reading head landmarks from your photo.") },
24736
24873
  { title: t2("MAPPING CIRCUMFERENCE"), desc: t2("Estimating head width and depth.") },
24737
24874
  { title: t2("MATCHING HAT SIZE"), desc: t2("Comparing your circumference to the size chart.") },
24738
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
24875
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size.") }
24739
24876
  ] : category === "face" ? [
24740
24877
  { title: t2("DETECTING FACE"), desc: t2("Identifying 478 face landmarks in your photo.") },
24741
24878
  { title: t2("CALIBRATING SCALE"), desc: t2("Using iris size as the pixel-to-mm anchor.") },
24742
24879
  { title: t2("MEASURING FRAME"), desc: t2("Mapping bridge, lens width and temple length.") },
24743
24880
  { title: t2("MATCHING FRAME SIZE"), desc: t2("Comparing your measurements to the size chart.") },
24744
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
24881
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size.") }
24745
24882
  ] : [
24746
24883
  // Body + foot fall through here — broadest set of stages so long
24747
24884
  // Gemini estimates still have fresh text to cycle through.
@@ -24749,7 +24886,7 @@ function StageCycler({
24749
24886
  { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions.") },
24750
24887
  { title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
24751
24888
  { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
24752
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
24889
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size.") }
24753
24890
  ];
24754
24891
  const TOTAL_MS = 6e3;
24755
24892
  const LAST_HOLD_MS = 1e3;
@@ -25186,7 +25323,7 @@ function SectionDetailView({
25186
25323
  const details = sectionResult?.matchDetails ?? [];
25187
25324
  const BAD_FIT = /tight|loose|large|small|very/i;
25188
25325
  const hasBadFit = details.some((d) => BAD_FIT.test(d.fit || ""));
25189
- return hasBadFit ? t2("Not Recommended") : t2("Your Selection");
25326
+ return hasBadFit ? t2("Not Suggested") : t2("Your Selection");
25190
25327
  }, [isRecommended, sectionResult, t2]);
25191
25328
  const sizeFitPrefix = (() => {
25192
25329
  if (renderRaw || isFootwear) return "";
@@ -25587,7 +25724,7 @@ function SectionDetailView({
25587
25724
  {
25588
25725
  className: "ps-msd-card-eyebrow",
25589
25726
  style: displaySize !== backendSize ? { color: "#b45309", fontWeight: 700 } : void 0,
25590
- children: displaySize === backendSize ? t2("RECOMMENDED SIZE") : t2("YOUR CHOICE · NOT RECOMMENDED")
25727
+ children: displaySize === backendSize ? t2("SUGGESTED SIZE") : t2("YOUR CHOICE · NOT SUGGESTED")
25591
25728
  }
25592
25729
  ),
25593
25730
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px", marginTop: "6px", marginBottom: "4px" }, children: [
@@ -25778,7 +25915,7 @@ function SectionDetailView({
25778
25915
  ] })
25779
25916
  ] }) });
25780
25917
  }
25781
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sec-detail", style: { padding: "1.5vw", display: "flex", flexDirection: "column", height: "100%", background: "#F8F9FA" }, children: [
25918
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sec-detail", style: { padding: "1.2vw 0.95vw 1vw", display: "flex", flexDirection: "column", height: "100%", background: "#F8F9FA" }, children: [
25782
25919
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { flex: 1, minHeight: 0, overflowY: "auto", scrollbarWidth: "thin", scrollbarColor: "rgba(0,0,0,0.04) transparent", display: sectionFound === false ? "flex" : "block", alignItems: sectionFound === false ? "center" : void 0, justifyContent: sectionFound === false ? "center" : void 0 }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
25783
25920
  /* @__PURE__ */ jsxRuntimeExports.jsx(
25784
25921
  "span",
@@ -25790,7 +25927,7 @@ function SectionDetailView({
25790
25927
  textTransform: "uppercase",
25791
25928
  letterSpacing: "0.12em"
25792
25929
  },
25793
- children: guideOnly ? t2("Size Guide") : isRecommended ? t2("Recommended Size") : t2("Your Choice · Not Recommended")
25930
+ children: guideOnly ? t2("Size Guide") : isRecommended ? t2("Suggested Size") : t2("Your Choice · Not Suggested")
25794
25931
  }
25795
25932
  ),
25796
25933
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5vw", marginTop: "0.35vw", marginBottom: "0.4vw" }, children: [
@@ -25950,11 +26087,11 @@ function SectionDetailView({
25950
26087
  ] })
25951
26088
  ] }) }),
25952
26089
  profileCompletionCta && /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, t: t2 }),
25953
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", paddingTop: "0.6vw", borderTop: "1px solid rgba(0,0,0,0.06)", flexShrink: 0 }, children: [
26090
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sec-detail-footer", style: { display: "flex", alignItems: "center", justifyContent: "space-between", paddingTop: "0.6vw", borderTop: "1px solid rgba(0,0,0,0.06)", flexShrink: 0 }, children: [
25954
26091
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-bp-back-btn", onClick: onBack, type: "button", style: { fontSize: "0.7vw" }, children: [
25955
26092
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
25956
26093
  " ",
25957
- backLabel || t2("Back to sections")
26094
+ backLabel || t2("Back")
25958
26095
  ] }),
25959
26096
  onTryOn ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
25960
26097
  "button",
@@ -25988,7 +26125,7 @@ function SectionDetailView({
25988
26125
  tryOnProcessing ? `${t2("Generating try-on…")}${tryOnElapsedS > 0 ? ` ${tryOnElapsedS}s` : ""}` : t2("Try It On")
25989
26126
  ]
25990
26127
  }
25991
- ) : resultActionNode ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-action-group", children: resultActionNode }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
26128
+ ) : resultActionNode ? resultActionNode : /* @__PURE__ */ jsxRuntimeExports.jsxs(
25992
26129
  "button",
25993
26130
  {
25994
26131
  onClick: continueLabel ? onContinue || onBack : onBack,
@@ -26051,6 +26188,7 @@ function SizeResultView({
26051
26188
  bodyLandmarks,
26052
26189
  faceLandmarks = null,
26053
26190
  measurementType = "body",
26191
+ isAccessoryProduct = false,
26054
26192
  estimationDone = false,
26055
26193
  activeSection,
26056
26194
  setActiveSection,
@@ -26110,9 +26248,10 @@ function SizeResultView({
26110
26248
  ) });
26111
26249
  }
26112
26250
  const allowAddToBag = options?.allowAddToBag !== false;
26251
+ const showContinue = options?.showContinue !== false;
26113
26252
  if (allowAddToBag && canAddToBag) {
26114
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-action-group", children: [
26115
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
26253
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-v2-action-group${!showContinue ? " ps-tryon-v2-action-group-single" : ""}`, children: [
26254
+ showContinue && /* @__PURE__ */ jsxRuntimeExports.jsxs(
26116
26255
  "button",
26117
26256
  {
26118
26257
  className: "ps-tryon-v2-cta ps-tryon-v2-cta-secondary",
@@ -26141,6 +26280,9 @@ function SizeResultView({
26141
26280
  )
26142
26281
  ] });
26143
26282
  }
26283
+ if (!showContinue) {
26284
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-action-group ps-tryon-v2-action-group-single", "aria-hidden": "true" });
26285
+ }
26144
26286
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
26145
26287
  "button",
26146
26288
  {
@@ -26177,13 +26319,13 @@ function SizeResultView({
26177
26319
  return /^standard(?:\s+size)?$/i.test(cleaned);
26178
26320
  });
26179
26321
  if (standardIdx >= 0) return standardIdx;
26180
- const recommended = String(sizingResult?.recommendedSize || "").trim();
26181
- if (recommended) {
26322
+ const suggested = String(sizingResult?.recommendedSize || "").trim();
26323
+ if (suggested) {
26182
26324
  const byRecommendedValue = sizeGuide.headers.findIndex((h, c) => {
26183
26325
  const cleaned = h.trim().replace(/\(.*?\)/g, "").trim();
26184
26326
  const sizeLikeHeader = /^(size|sizes|taglia|größe|taille|standard)$/i.test(cleaned);
26185
26327
  const alphaSizeColumn = rows.some((r2) => /^(XXS|XS|S|M|L|XL|XXL|XXXL|[3-9]XL|ONE SIZE)$/i.test(cellVal(r2, c, h)));
26186
- return (sizeLikeHeader || alphaSizeColumn) && rows.some((r2) => cellVal(r2, c, h) === recommended);
26328
+ return (sizeLikeHeader || alphaSizeColumn) && rows.some((r2) => cellVal(r2, c, h) === suggested);
26187
26329
  });
26188
26330
  if (byRecommendedValue >= 0) return byRecommendedValue;
26189
26331
  }
@@ -26481,7 +26623,7 @@ function SizeResultView({
26481
26623
  const profileCompletionCta = showProfileCompletionCta && onProfileCompletionCta ? { onClick: onProfileCompletionCta } : null;
26482
26624
  const carouselItems = productCarouselItems?.filter((item) => item.image) ?? [];
26483
26625
  const hasCarousel = carouselItems.length > 0 || !!(productImages && productImages.length > 0);
26484
- const isAccessory = measurementType === "face" || measurementType === "head" || measurementType === "wrist";
26626
+ const isAccessory = isAccessoryProduct || measurementType === "face" || measurementType === "head" || measurementType === "wrist";
26485
26627
  const suppressFitOverlayActions = isAccessory || measurementType === "foot";
26486
26628
  const noFit = sizingResult?.found === false;
26487
26629
  const guideOnlyResult = !!(sizingResult?.guideOnly || sizingResult?.oneSize);
@@ -26583,7 +26725,7 @@ function SizeResultView({
26583
26725
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle, className: "ps-tryon-sr-product-img" }) }),
26584
26726
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "0.8vw" }, children: [
26585
26727
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner" }),
26586
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { color: "var(--ps-text-muted)", fontSize: "0.8vw" }, children: t2("Generating your size recommendation...") })
26728
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { color: "var(--ps-text-muted)", fontSize: "0.8vw" }, children: t2("Generating your suggested size...") })
26587
26729
  ] })
26588
26730
  ] }),
26589
26731
  isMobile && isSnapProcessing && previewUrl && /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -26655,7 +26797,7 @@ function SizeResultView({
26655
26797
  })(),
26656
26798
  onBack: () => setActiveSection(null),
26657
26799
  onContinue: handleContinueAction,
26658
- resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta() : void 0,
26800
+ resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta({ showContinue: false }) : void 0,
26659
26801
  internationalSizes: entry.secResult?.internationalSizes,
26660
26802
  productImage: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
26661
26803
  productTitle,
@@ -26756,7 +26898,7 @@ function SizeResultView({
26756
26898
  })(),
26757
26899
  onBack: () => setActiveSection(null),
26758
26900
  onContinue: handleContinueAction,
26759
- resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta() : void 0,
26901
+ resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta({ showContinue: false }) : void 0,
26760
26902
  internationalSizes: entry.secResult?.internationalSizes,
26761
26903
  tryOnProcessing,
26762
26904
  tryOnStartedAt,
@@ -26893,9 +27035,9 @@ function SizeResultView({
26893
27035
  resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, onSubmit: onTryOnFeedbackSubmit }) })
26894
27036
  ] })
26895
27037
  ] }),
26896
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel ps-tryon-v2-result-panel", children: [
27038
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel ps-tryon-v2-result-panel ps-tryon-v2-multi-result-panel", children: [
26897
27039
  profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-profile-head ps-expanded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, placement: "header", t: t2 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-copy", children: [
26898
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Size Recommendation") }),
27040
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Suggested Size") }),
26899
27041
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap any section for detailed breakdown") })
26900
27042
  ] }),
26901
27043
  mismatchNotice,
@@ -26926,7 +27068,7 @@ function SizeResultView({
26926
27068
  "span",
26927
27069
  {
26928
27070
  className: `ps-tryon-sr-card-v2-rec-pill${isOverridden ? " is-overridden" : ""}`,
26929
- children: isOverridden ? t2("YOUR SELECTION") : t2("RECOMMENDED")
27071
+ children: isOverridden ? t2("YOUR SELECTION") : t2("SUGGESTED")
26930
27072
  }
26931
27073
  ),
26932
27074
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-sr-card-v2-view", children: [
@@ -27012,7 +27154,7 @@ function SizeResultView({
27012
27154
  backLabel: t2("Back"),
27013
27155
  internationalSizes: singleInternationalSizes,
27014
27156
  onTryOn: canAddToBag || isHistoryResult || resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
27015
- resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta() : void 0,
27157
+ resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta({ showContinue: false }) : void 0,
27016
27158
  continueLabel: resultImageUrl ? resolvedContinueShoppingLabel : void 0,
27017
27159
  tryOnProcessing,
27018
27160
  tryOnStartedAt,
@@ -27109,7 +27251,7 @@ function SizeResultView({
27109
27251
  backLabel: t2("Back"),
27110
27252
  internationalSizes: singleInternationalSizes,
27111
27253
  onTryOn: canAddToBag || isHistoryResult || resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
27112
- resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta() : void 0,
27254
+ resultActionNode: canAddToBag || isHistoryResult || !!resultImageUrl || vtoExcluded ? renderShoppingCta({ showContinue: false }) : void 0,
27113
27255
  continueLabel: resultImageUrl ? resolvedContinueShoppingLabel : void 0,
27114
27256
  tryOnProcessing,
27115
27257
  tryOnStartedAt,
@@ -27131,10 +27273,10 @@ function SizeResultView({
27131
27273
  const rawLabelText = pendingCustomSizes[sectionName]?.displayLabel || singleResult.recommendedSize || singleResult.sizeLabel || (guideOnlyResult ? t2("One Size") : "—");
27132
27274
  const labelText = measurementType === "foot" ? formatShoeSizeLabel(rawLabelText, shoeUserGender) : rawLabelText;
27133
27275
  const isLong = labelText.length > 12;
27134
- const badgeText = guideOnlyResult ? t2("SIZE GUIDE") : pendingCustomSizes[sectionName] ? t2("YOUR SELECTION") : t2("RECOMMENDED");
27276
+ const badgeText = guideOnlyResult ? t2("SIZE GUIDE") : pendingCustomSizes[sectionName] ? t2("YOUR SELECTION") : t2("SUGGESTED");
27135
27277
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
27136
27278
  profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-result-head", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-profile-head ps-expanded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, placement: "header", t: t2 }) }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-copy ps-single-result-copy", children: [
27137
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Size Recommendation") }),
27279
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Suggested Size") }),
27138
27280
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap the card for detailed breakdown") })
27139
27281
  ] }),
27140
27282
  profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-sep" }) : null,
@@ -27271,7 +27413,7 @@ function SizeResultView({
27271
27413
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Leave space above your head") }),
27272
27414
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Good lighting, plain background") })
27273
27415
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
27274
- /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Form-fitting clothing is recommended") }),
27416
+ /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Wear fitted, simple clothing") }),
27275
27417
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Standing 2-3 meters from camera") }),
27276
27418
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Neutral background with good lighting") })
27277
27419
  ] }) })
@@ -27807,7 +27949,7 @@ function PhotoGuideView({
27807
27949
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Leave space above your head") }),
27808
27950
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Good lighting, plain background") })
27809
27951
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
27810
- /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Form-fitting clothing is recommended") }),
27952
+ /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Wear fitted, simple clothing") }),
27811
27953
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Standing 2-3 meters from camera") }),
27812
27954
  /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Neutral background with good lighting") })
27813
27955
  ] }) })
@@ -27987,7 +28129,7 @@ function ProcessingView({
27987
28129
  }
27988
28130
  }, []);
27989
28131
  const aiFacts = [
27990
- t2("Our model is analyzing 150+ body landmarks for your size recommendation"),
28132
+ t2("Our model is analyzing 150+ body landmarks for your size suggestion"),
27991
28133
  t2("Calibrating fabric drape against your body proportions"),
27992
28134
  t2("Cross-checking fit against millions of garment patterns"),
27993
28135
  t2("Rendering shadows and highlights to match your photo's lighting")
@@ -28227,7 +28369,7 @@ function MiniSelect$1({
28227
28369
  isOpen,
28228
28370
  onToggle,
28229
28371
  onSelect,
28230
- direction = "down"
28372
+ direction = "up"
28231
28373
  }) {
28232
28374
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-mini-select", "data-open": isOpen ? "true" : "false", "data-dir": direction, children: [
28233
28375
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -29661,10 +29803,10 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, dire
29661
29803
  mode === "image" && imageStep === "calculating" && (() => {
29662
29804
  const stages = [
29663
29805
  { title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo.") },
29664
- { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size recommendation.") },
29806
+ { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size suggestion.") },
29665
29807
  { title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
29666
29808
  { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
29667
- { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
29809
+ { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your suggested size.") }
29668
29810
  ];
29669
29811
  const stage = stages[Math.min(scanStageIdx, stages.length - 1)] ?? stages[0];
29670
29812
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-fade-in", style: { display: "flex", flexDirection: "column", flex: 1, overflow: "auto" }, children: estimating ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: "1.2vw", padding: "1.5vw", flex: 1 }, children: [
@@ -30444,7 +30586,7 @@ function BasicsStepMobile({
30444
30586
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-root", children: [
30445
30587
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-header", children: [
30446
30588
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bpm-title", children: t2("Body Measurements") }),
30447
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-bpm-subtitle", children: t2("Enter your details for a bespoke size recommendation") })
30589
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-bpm-subtitle", children: t2("Enter your details for a bespoke size suggestion") })
30448
30590
  ] }),
30449
30591
  activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card", children: [
30450
30592
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card-copy", children: [
@@ -31179,7 +31321,7 @@ function MiniSelect({
31179
31321
  isOpen,
31180
31322
  onToggle,
31181
31323
  onSelect,
31182
- direction = "down"
31324
+ direction = "up"
31183
31325
  }) {
31184
31326
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-mini-select", "data-open": isOpen ? "true" : "false", "data-dir": direction, children: [
31185
31327
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -31990,7 +32132,8 @@ function BodyProfileView({
31990
32132
  setBandSize(null);
31991
32133
  setCupSize(null);
31992
32134
  setInlineBraOpen(null);
31993
- }
32135
+ },
32136
+ direction: "up"
31994
32137
  }
31995
32138
  ) })
31996
32139
  ] }),
@@ -32007,7 +32150,8 @@ function BodyProfileView({
32007
32150
  onSelect: (v2) => {
32008
32151
  setBandSize(v2);
32009
32152
  setInlineBraOpen(null);
32010
- }
32153
+ },
32154
+ direction: "up"
32011
32155
  }
32012
32156
  ) })
32013
32157
  ] }),
@@ -32066,6 +32210,7 @@ function BodyProfileView({
32066
32210
  const analyzeDisabled = analyzeMissing.length > 0;
32067
32211
  const analyzeLabel = analyzeDisabled ? analyzeMissing[0] ?? t2("Analyze My Size") : t2("Analyze My Size");
32068
32212
  const compactHeightWeightAccessory = simplePhotoOnly && simpleAccessoryLayout && !isShoeReferenceMode;
32213
+ const maleStandardPhotoDetails = !isWomen && !simplePhotoOnly && !isShoeReferenceMode;
32069
32214
  if (isMobile) {
32070
32215
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-wrapper", children: [
32071
32216
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-scan-progress", children: [
@@ -32245,7 +32390,7 @@ function BodyProfileView({
32245
32390
  overflow: "hidden"
32246
32391
  },
32247
32392
  children: [
32248
- !photoPreview && /* @__PURE__ */ jsxRuntimeExports.jsxs(
32393
+ !photoPreview && !compactHeightWeightAccessory && !maleStandardPhotoDetails && /* @__PURE__ */ jsxRuntimeExports.jsxs(
32249
32394
  "button",
32250
32395
  {
32251
32396
  type: "button",
@@ -32262,7 +32407,7 @@ function BodyProfileView({
32262
32407
  ]
32263
32408
  }
32264
32409
  ),
32265
- !photoPreview && photoHelpOpen && /* @__PURE__ */ jsxRuntimeExports.jsxs(
32410
+ !photoPreview && !compactHeightWeightAccessory && !maleStandardPhotoDetails && photoHelpOpen && /* @__PURE__ */ jsxRuntimeExports.jsxs(
32266
32411
  "div",
32267
32412
  {
32268
32413
  role: "dialog",
@@ -32556,19 +32701,118 @@ function BodyProfileView({
32556
32701
  flex: compactHeightWeightAccessory ? "0 1 min(34vw, 360px)" : 1,
32557
32702
  display: "flex",
32558
32703
  flexDirection: "column",
32559
- justifyContent: compactHeightWeightAccessory ? "center" : "flex-start",
32704
+ justifyContent: "flex-start",
32560
32705
  position: "relative",
32561
- gap: compactHeightWeightAccessory ? "1.1vw" : "0.8vw",
32706
+ gap: compactHeightWeightAccessory ? "0.8vw" : "0.8vw",
32562
32707
  minWidth: compactHeightWeightAccessory ? "280px" : void 0
32563
32708
  }, children: isShoeReferenceMode ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-shoe-ref-desktop", children: renderShoeReferenceFields() }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
32564
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-bp-photo-details-head${compactHeightWeightAccessory ? " ps-bp-photo-details-head-simple" : ""}`, children: [
32565
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: t2("Body details") }),
32566
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-system-toggle ps-bp-system-toggle-compact", children: [
32567
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${!isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToMetric, type: "button", children: t2("Metric") }),
32568
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToImperial, type: "button", children: t2("Imperial") })
32569
- ] })
32709
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
32710
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-bp-photo-details-head${compactHeightWeightAccessory || maleStandardPhotoDetails ? " ps-bp-photo-details-head-simple" : ""}`, children: [
32711
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: t2("Body details") }),
32712
+ compactHeightWeightAccessory || maleStandardPhotoDetails ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
32713
+ "button",
32714
+ {
32715
+ type: "button",
32716
+ onClick: (e) => {
32717
+ e.stopPropagation();
32718
+ setPhotoHelpOpen((v2) => !v2);
32719
+ },
32720
+ "aria-label": t2("How to take a good photo"),
32721
+ title: t2("How to take a good photo"),
32722
+ className: `ps-bp-photo-help-chip${photoHelpOpen ? " ps-active" : ""}`,
32723
+ style: { position: "static", maxWidth: "none", flexShrink: 0 },
32724
+ children: [
32725
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-photo-help-chip-mark", "aria-hidden": "true", children: "?" }),
32726
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("How to take a good photo") })
32727
+ ]
32728
+ }
32729
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-system-toggle ps-bp-system-toggle-compact", children: [
32730
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${!isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToMetric, type: "button", children: t2("Metric") }),
32731
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToImperial, type: "button", children: t2("Imperial") })
32732
+ ] })
32733
+ ] }),
32734
+ (compactHeightWeightAccessory || maleStandardPhotoDetails) && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { margin: "0.2vw 0 0", fontSize: "0.65vw", color: "var(--ps-text-muted)" }, children: t2("These calibrate the AI — all required.") })
32735
+ ] }),
32736
+ (compactHeightWeightAccessory || maleStandardPhotoDetails) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-bp-system-toggle ps-bp-system-toggle-compact${maleStandardPhotoDetails ? " ps-bp-system-toggle-large" : ""}`, style: { alignSelf: "center", marginTop: "1.2vw" }, children: [
32737
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${!isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToMetric, type: "button", children: t2("Metric") }),
32738
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToImperial, type: "button", children: t2("Imperial") })
32570
32739
  ] }),
32571
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { marginTop: compactHeightWeightAccessory ? "0.35vw" : "0.15vw", marginBottom: 0, minHeight: 0 }, children: [
32740
+ (compactHeightWeightAccessory || maleStandardPhotoDetails) && photoHelpOpen && /* @__PURE__ */ jsxRuntimeExports.jsxs(
32741
+ "div",
32742
+ {
32743
+ role: "dialog",
32744
+ "aria-label": t2("How to take the best photo"),
32745
+ style: {
32746
+ position: "absolute",
32747
+ top: "2.2vw",
32748
+ right: 0,
32749
+ width: "min(360px, 22vw)",
32750
+ background: "#FFFFFF",
32751
+ border: "1px solid var(--ps-border-subtle)",
32752
+ borderRadius: "0.8vw",
32753
+ boxShadow: "0 20px 40px -12px rgba(17,24,39,0.25), 0 8px 16px -8px rgba(17,24,39,0.15)",
32754
+ padding: "0.8vw 1vw",
32755
+ display: "flex",
32756
+ flexDirection: "column",
32757
+ gap: "0.6vw",
32758
+ maxHeight: "min(70dvh, 520px)",
32759
+ overflowY: "auto",
32760
+ zIndex: 5
32761
+ },
32762
+ children: [
32763
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
32764
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.8vw", fontWeight: 700, color: "var(--ps-text-primary)" }, children: t2("How to take the best photo") }),
32765
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
32766
+ "button",
32767
+ {
32768
+ type: "button",
32769
+ onClick: () => setPhotoHelpOpen(false),
32770
+ "aria-label": t2("Close"),
32771
+ style: { width: "1.4vw", height: "1.4vw", borderRadius: "50%", background: "transparent", border: "none", color: "var(--ps-text-muted)", cursor: "pointer", fontSize: "1vw", lineHeight: 1 },
32772
+ children: "×"
32773
+ }
32774
+ )
32775
+ ] }),
32776
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "#ddfbe7", borderRadius: "0.5vw", padding: "0.55vw 0.75vw" }, children: [
32777
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { color: "#1c9d4c", fontSize: "0.7vw", fontWeight: 700, marginBottom: "0.3vw" }, children: [
32778
+ "✓ ",
32779
+ t2("Do")
32780
+ ] }),
32781
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { fontSize: "0.6vw", color: "var(--ps-text-primary)", lineHeight: 1.6 }, children: [
32782
+ t2("Stand facing the camera with your full body in frame"),
32783
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
32784
+ t2("Use natural or even lighting"),
32785
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
32786
+ t2("Wear fitted, simple clothing"),
32787
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
32788
+ t2("Choose a plain background")
32789
+ ] })
32790
+ ] }),
32791
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "#fee2e2", borderRadius: "0.5vw", padding: "0.55vw 0.75vw" }, children: [
32792
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { color: "#dc2626", fontSize: "0.7vw", fontWeight: 700, marginBottom: "0.3vw" }, children: [
32793
+ "✕ ",
32794
+ t2("Don't")
32795
+ ] }),
32796
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { fontSize: "0.6vw", color: "var(--ps-text-primary)", lineHeight: 1.6 }, children: [
32797
+ t2("Don't wear loose, baggy, or layered clothing"),
32798
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
32799
+ t2("Don't sit, pose, or bend your body"),
32800
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
32801
+ t2("Don't use strong backlighting")
32802
+ ] })
32803
+ ] }),
32804
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "#dbeafe", borderRadius: "0.5vw", padding: "0.55vw 0.75vw", fontSize: "0.58vw", color: "var(--ps-text-primary)", lineHeight: 1.5 }, children: [
32805
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("strong", { children: [
32806
+ t2("Quick Tip"),
32807
+ ":"
32808
+ ] }),
32809
+ " ",
32810
+ t2("The simpler your photo is, the more accurate your virtual try-on results will be.")
32811
+ ] })
32812
+ ]
32813
+ }
32814
+ ),
32815
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { marginTop: compactHeightWeightAccessory || maleStandardPhotoDetails ? "auto" : "0.15vw", marginBottom: compactHeightWeightAccessory || maleStandardPhotoDetails ? "auto" : 0, minHeight: 0 }, children: [
32572
32816
  activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card ps-bp-profile-card-compact", children: [
32573
32817
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card-copy", children: [
32574
32818
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-profile-card-eyebrow", children: t2("Active Profile") }),
@@ -32612,7 +32856,8 @@ function BodyProfileView({
32612
32856
  setBandSize(null);
32613
32857
  setCupSize(null);
32614
32858
  setInlineBraOpen(null);
32615
- }
32859
+ },
32860
+ direction: "up"
32616
32861
  }
32617
32862
  ) })
32618
32863
  ] }),
@@ -32629,7 +32874,8 @@ function BodyProfileView({
32629
32874
  onSelect: (v2) => {
32630
32875
  setBandSize(v2);
32631
32876
  setInlineBraOpen(null);
32632
- }
32877
+ },
32878
+ direction: "up"
32633
32879
  }
32634
32880
  ) })
32635
32881
  ] }),
@@ -34880,7 +35126,7 @@ function PrimeStyleTryonInner({
34880
35126
  const key = getApiKey();
34881
35127
  const url = getApiUrl(apiUrl);
34882
35128
  apiRef.current = new ApiClient(key, url);
34883
- sseRef.current = shouldUseShopifyCartAttribution(url) ? null : new SseClient(apiRef.current.getStreamUrl());
35129
+ sseRef.current = null;
34884
35130
  } catch {
34885
35131
  }
34886
35132
  return () => {
@@ -34889,6 +35135,52 @@ function PrimeStyleTryonInner({
34889
35135
  if (pollingRef.current) clearInterval(pollingRef.current);
34890
35136
  };
34891
35137
  }, [apiUrl]);
35138
+ const reportSdkEvent = reactExports.useCallback((eventType, input = {}) => {
35139
+ if (shouldUseShopifyCartAttribution(apiUrl)) return;
35140
+ const client = apiRef.current;
35141
+ if (!client) return;
35142
+ void client.reportEvent({
35143
+ eventType,
35144
+ productId: effectiveProductId,
35145
+ productTitle: restoredProductTitle || productTitle,
35146
+ productUrl: restoredProductUrl || effectiveProductUrl,
35147
+ jobId: input.jobId ?? currentTryOnJobIdRef.current ?? void 0,
35148
+ recommendedSize: input.recommendedSize ?? sizingResultRef.current?.recommendedSize,
35149
+ metadata: input.metadata
35150
+ }).catch(() => {
35151
+ });
35152
+ }, [apiUrl, effectiveProductId, effectiveProductUrl, productTitle, restoredProductTitle, restoredProductUrl]);
35153
+ const reportSdkClientError = reactExports.useCallback((input) => {
35154
+ if (shouldUseShopifyCartAttribution(apiUrl)) return;
35155
+ const client = apiRef.current;
35156
+ if (!client) return;
35157
+ void client.reportClientError({
35158
+ ...input,
35159
+ productId: effectiveProductId,
35160
+ productTitle: restoredProductTitle || productTitle,
35161
+ productUrl: restoredProductUrl || effectiveProductUrl,
35162
+ jobId: input.jobId ?? currentTryOnJobIdRef.current ?? void 0
35163
+ }).catch(() => {
35164
+ });
35165
+ }, [apiUrl, effectiveProductId, effectiveProductUrl, productTitle, restoredProductTitle, restoredProductUrl]);
35166
+ const productViewLoggedRef = reactExports.useRef(null);
35167
+ reactExports.useEffect(() => {
35168
+ const key = `${effectiveProductId || ""}|${effectiveProductUrl || ""}`;
35169
+ if (!key.trim() || productViewLoggedRef.current === key) return;
35170
+ productViewLoggedRef.current = key;
35171
+ if (shouldUseShopifyCartAttribution(apiUrl)) {
35172
+ logProductView({ productId: effectiveProductId, productTitle });
35173
+ return;
35174
+ }
35175
+ reportSdkEvent("PRODUCT_VIEW", {
35176
+ metadata: {
35177
+ productUrl: effectiveProductUrl,
35178
+ productFitType: resolvedProductFitType,
35179
+ productCategory,
35180
+ productSubcategory
35181
+ }
35182
+ });
35183
+ }, [apiUrl, effectiveProductId, effectiveProductUrl, productCategory, productSubcategory, productTitle, reportSdkEvent, resolvedProductFitType]);
34892
35184
  const pickFireCountRef = reactExports.useRef(0);
34893
35185
  const toBackendFetchableImageUrl = reactExports.useCallback((url) => {
34894
35186
  const trimmed = String(url || "").trim();
@@ -35429,10 +35721,11 @@ function PrimeStyleTryonInner({
35429
35721
  });
35430
35722
  const handleOpen = reactExports.useCallback(() => {
35431
35723
  console.log("[ps-sdk] handleOpen fired — opening modal");
35724
+ reportSdkEvent("SDK_OPENED", { metadata: { view: "body-profile" } });
35432
35725
  setBodyProfileInitialStep(null);
35433
35726
  setView("body-profile");
35434
35727
  onOpen?.();
35435
- }, [onOpen]);
35728
+ }, [onOpen, reportSdkEvent]);
35436
35729
  const handleClose = reactExports.useCallback(() => {
35437
35730
  const tryOnInFlight = tryOnProcessing;
35438
35731
  setView("idle");
@@ -35522,12 +35815,28 @@ function PrimeStyleTryonInner({
35522
35815
  if (!isValidImageFile(file)) {
35523
35816
  setErrorMessage(t2("Please upload a JPEG, PNG, or WebP image."));
35524
35817
  setView("error");
35818
+ reportSdkClientError({
35819
+ message: "Invalid image file type",
35820
+ code: "INVALID_FILE",
35821
+ component: "PhotoUpload",
35822
+ view,
35823
+ severity: "low",
35824
+ metadata: { fileType: file.type, fileSize: file.size }
35825
+ });
35525
35826
  onError?.({ message: "Invalid file type", code: "INVALID_FILE" });
35526
35827
  return;
35527
35828
  }
35528
35829
  if (file.size > 10 * 1024 * 1024) {
35529
35830
  setErrorMessage(t2("Image must be under 10MB."));
35530
35831
  setView("error");
35832
+ reportSdkClientError({
35833
+ message: "Image file too large",
35834
+ code: "FILE_TOO_LARGE",
35835
+ component: "PhotoUpload",
35836
+ view,
35837
+ severity: "low",
35838
+ metadata: { fileType: file.type, fileSize: file.size }
35839
+ });
35531
35840
  onError?.({ message: "File too large", code: "FILE_TOO_LARGE" });
35532
35841
  return;
35533
35842
  }
@@ -35536,13 +35845,23 @@ function PrimeStyleTryonInner({
35536
35845
  modelImageIdRef.current = null;
35537
35846
  const objUrl = URL.createObjectURL(file);
35538
35847
  setPreviewUrl(objUrl);
35848
+ reportSdkEvent("PHOTO_UPLOADED", {
35849
+ metadata: { fileType: file.type, fileSize: file.size, view }
35850
+ });
35539
35851
  onUpload?.(file);
35540
35852
  modelPoseRef.current = null;
35541
35853
  detectMeasurementLines(objUrl).then((lines) => {
35542
35854
  modelPoseRef.current = lines;
35543
- }).catch(() => {
35855
+ }).catch((error) => {
35856
+ reportSdkClientError({
35857
+ message: error instanceof Error ? error.message : "Pose detection failed",
35858
+ code: "POSE_DETECTION_FAILED",
35859
+ component: "MediaPipe",
35860
+ view,
35861
+ severity: "low"
35862
+ });
35544
35863
  });
35545
- }, [onUpload, onError]);
35864
+ }, [onUpload, onError, reportSdkClientError, reportSdkEvent, t2, view]);
35546
35865
  const handleRemovePreview = reactExports.useCallback(() => {
35547
35866
  setSelectedFile(null);
35548
35867
  if (previewUrl) URL.revokeObjectURL(previewUrl);
@@ -35611,12 +35930,21 @@ function PrimeStyleTryonInner({
35611
35930
  setTryOnProcessing(false);
35612
35931
  setTryOnStartedAt(null);
35613
35932
  const msg = update.error || t2("Try-on generation failed");
35933
+ reportSdkClientError({
35934
+ message: msg,
35935
+ code: "TRYON_GENERATION_FAILED",
35936
+ component: "TryOn",
35937
+ view,
35938
+ severity: "medium",
35939
+ jobId: update.galleryId,
35940
+ metadata: { status: update.status }
35941
+ });
35614
35942
  setErrorMessage(msg);
35615
35943
  setView("error");
35616
35944
  onError?.({ message: msg });
35617
35945
  }
35618
35946
  }
35619
- }, [apiUrl, effectiveProductId, productTitle, onComplete, onError, cleanupJob]);
35947
+ }, [apiUrl, effectiveProductId, productTitle, onComplete, onError, cleanupJob, reportSdkClientError, t2, view]);
35620
35948
  const dynamicFields = reactExports.useMemo(() => {
35621
35949
  if (sizeGuide?.found && sizeGuide.requiredFields && sizeGuide.requiredFields.length > 0) {
35622
35950
  return sizeGuide.requiredFields;
@@ -35630,6 +35958,14 @@ function PrimeStyleTryonInner({
35630
35958
  const method = methodOverride || sizingMethod;
35631
35959
  const baseUrl = getApiUrl(apiUrl);
35632
35960
  const key = getApiKey();
35961
+ reportSdkEvent("SIZING_STARTED", {
35962
+ metadata: {
35963
+ method,
35964
+ measurementType,
35965
+ productFitType: resolvedProductFitType,
35966
+ hasSizeGuide: !!sizeGuide?.found
35967
+ }
35968
+ });
35633
35969
  if (measurementType === "face" || measurementType === "head") {
35634
35970
  const f2 = formRef.current;
35635
35971
  const toNum = (v2) => {
@@ -35688,23 +36024,61 @@ function PrimeStyleTryonInner({
35688
36024
  const data = await resp.json();
35689
36025
  await minVisible;
35690
36026
  if (data?.found === false) {
36027
+ reportSdkEvent("SIZING_FAILED", {
36028
+ metadata: {
36029
+ reason: data?.reasoning || "NO_MATCH",
36030
+ measurementType,
36031
+ found: false
36032
+ }
36033
+ });
35691
36034
  setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
35692
36035
  setView("no-chart");
35693
36036
  setEstimationDone(true);
35694
36037
  return;
35695
36038
  }
35696
36039
  setSizingResult(data);
36040
+ reportSdkEvent("SIZE_RECOMMENDATION_SHOWN", {
36041
+ recommendedSize: data?.recommendedSize,
36042
+ metadata: {
36043
+ confidence: data?.confidence,
36044
+ measurementType,
36045
+ source: "face-recommend"
36046
+ }
36047
+ });
35697
36048
  onComplete?.(data);
35698
36049
  } else {
35699
36050
  const body = await resp.text().catch(() => "");
35700
36051
  console.error("[PS-SDK] face-recommend failed:", resp.status, body);
36052
+ reportSdkEvent("SIZING_FAILED", {
36053
+ metadata: { status: resp.status, measurementType, source: "face-recommend" }
36054
+ });
36055
+ reportSdkClientError({
36056
+ message: body || "Face/head sizing request failed",
36057
+ code: "FACE_RECOMMEND_FAILED",
36058
+ component: "Sizing",
36059
+ view,
36060
+ severity: "medium",
36061
+ metadata: { status: resp.status, measurementType }
36062
+ });
35701
36063
  await minVisible;
35702
- setErrorMessage(t2("Unable to get size recommendation. Please try again."));
36064
+ setErrorMessage(t2("Unable to get a size suggestion. Please try again."));
35703
36065
  setView("error");
35704
36066
  setEstimationDone(true);
35705
36067
  }
35706
36068
  } catch (err) {
35707
36069
  console.error("[PS-SDK] face-recommend network error:", err);
36070
+ reportSdkEvent("SIZING_FAILED", {
36071
+ metadata: { measurementType, source: "face-recommend", network: true }
36072
+ });
36073
+ reportSdkClientError({
36074
+ message: err instanceof Error ? err.message : "Face/head sizing network error",
36075
+ code: "FACE_RECOMMEND_NETWORK_ERROR",
36076
+ stack: err instanceof Error ? err.stack : void 0,
36077
+ component: "Sizing",
36078
+ view,
36079
+ severity: "medium",
36080
+ metadata: { measurementType }
36081
+ });
35708
36082
  await minVisible;
35709
36083
  setErrorMessage(t2("Unable to connect to sizing service. Please try again."));
35710
36084
  setView("error");
@@ -35765,6 +36139,17 @@ function PrimeStyleTryonInner({
35765
36139
  const qWeight = parseFloat(formRef.current.weight || "0");
35766
36140
  if (!qHeight || !qWeight) {
35767
36141
  console.error("[PS-SDK] submitSizing ABORT — qHeight:", qHeight, "qWeight:", qWeight, "formRef:", JSON.stringify(formRef.current));
36142
+ reportSdkEvent("SIZING_FAILED", {
36143
+ metadata: { reason: "missing_height_or_weight", method, measurementType }
36144
+ });
36145
+ reportSdkClientError({
36146
+ message: "Sizing submitted without height or weight",
36147
+ code: "SIZING_INPUT_MISSING",
36148
+ component: "Sizing",
36149
+ view,
36150
+ severity: "low",
36151
+ metadata: { method, measurementType, qHeight, qWeight }
36152
+ });
35768
36153
  setSizingLoading(false);
35769
36154
  return;
35770
36155
  }
@@ -35797,12 +36182,29 @@ function PrimeStyleTryonInner({
35797
36182
  const data = await res.json();
35798
36183
  console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
35799
36184
  if (data?.found === false) {
36185
+ reportSdkEvent("SIZING_FAILED", {
36186
+ metadata: {
36187
+ reason: data?.reasoning || "NO_MATCH",
36188
+ method,
36189
+ measurementType,
36190
+ found: false
36191
+ }
36192
+ });
35800
36193
  setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
35801
36194
  setView("no-chart");
35802
36195
  setEstimationDone(true);
35803
36196
  return;
35804
36197
  }
35805
36198
  setSizingResult(data);
36199
+ reportSdkEvent("SIZE_RECOMMENDATION_SHOWN", {
36200
+ recommendedSize: data?.recommendedSize,
36201
+ metadata: {
36202
+ confidence: data?.confidence,
36203
+ method,
36204
+ measurementType,
36205
+ found: data?.found
36206
+ }
36207
+ });
35806
36208
  onComplete?.(data);
35807
36209
  const m2 = payload.measurements || {};
35808
36210
  const qe2 = payload.quickEstimate || {};
@@ -35830,26 +36232,49 @@ function PrimeStyleTryonInner({
35830
36232
  } else {
35831
36233
  const errBody = await res.text().catch(() => "");
35832
36234
  console.error("[PS-SDK] Sizing recommend failed:", res.status, errBody);
35833
- setErrorMessage(t2("Unable to get size recommendation. Please try again."));
36235
+ reportSdkEvent("SIZING_FAILED", {
36236
+ metadata: { status: res.status, method, measurementType, source: "sizing-recommend" }
36237
+ });
36238
+ reportSdkClientError({
36239
+ message: errBody || "Sizing request failed",
36240
+ code: "SIZING_RECOMMEND_FAILED",
36241
+ component: "Sizing",
36242
+ view,
36243
+ severity: "medium",
36244
+ metadata: { status: res.status, method, measurementType }
36245
+ });
36246
+ setErrorMessage(t2("Unable to get a size suggestion. Please try again."));
35834
36247
  setView("error");
35835
36248
  setEstimationDone(true);
35836
36249
  }
35837
36250
  } catch (err) {
35838
36251
  console.error("[PS-SDK] Sizing recommend network error:", err);
36252
+ reportSdkEvent("SIZING_FAILED", {
36253
+ metadata: { method, measurementType, source: "sizing-recommend", network: true }
36254
+ });
36255
+ reportSdkClientError({
36256
+ message: err instanceof Error ? err.message : "Sizing network error",
36257
+ code: "SIZING_RECOMMEND_NETWORK_ERROR",
36258
+ stack: err instanceof Error ? err.stack : void 0,
36259
+ component: "Sizing",
36260
+ view,
36261
+ severity: "medium",
36262
+ metadata: { method, measurementType }
36263
+ });
35839
36264
  setErrorMessage(t2("Unable to connect to sizing service. Please try again."));
35840
36265
  setView("error");
35841
36266
  setEstimationDone(true);
35842
36267
  } finally {
35843
36268
  setSizingLoading(false);
35844
36269
  }
35845
- }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productContext, measurementType, dynamicFields, persistResultToProfile]);
36270
+ }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productContext, measurementType, resolvedProductFitType, dynamicFields, persistResultToProfile, reportSdkClientError, reportSdkEvent, t2, view]);
35846
36271
  const handleQuickEstimate = reactExports.useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
35847
36272
  if (!apiRef.current) {
35848
36273
  const msg = t2("SDK not configured. Please refresh and try again.");
35849
36274
  console.warn("[ps-sdk] handleQuickEstimate BAILED — apiRef is null. API key not loaded.");
35850
36275
  setErrorMessage(msg);
35851
36276
  setView("error");
35852
- onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
36277
+ onError?.({ message: msg, code: !apiRef.current ? "SDK_NOT_CONFIGURED" : "PHOTO_MISSING" });
35853
36278
  return;
35854
36279
  }
35855
36280
  getApiUrl(apiUrl);
@@ -36064,7 +36489,7 @@ function PrimeStyleTryonInner({
36064
36489
  await Promise.all([minVisible2, landmarksVisibleMin || Promise.resolve()]);
36065
36490
  const errBody = await recRes.text().catch(() => "");
36066
36491
  console.error("[ps-sdk] face-recommend failed:", recRes.status, errBody);
36067
- setErrorMessage(t2("Unable to get size recommendation. Please try manual measurements."));
36492
+ setErrorMessage(t2("Unable to get a size suggestion. Please try manual measurements."));
36068
36493
  setEstimationDone(true);
36069
36494
  setSizingLoading(false);
36070
36495
  setView("error");
@@ -36073,7 +36498,7 @@ function PrimeStyleTryonInner({
36073
36498
  } catch (err) {
36074
36499
  console.error("[ps-sdk] face-recommend failed:", err);
36075
36500
  await Promise.all([minVisible2, landmarksVisibleMin || Promise.resolve()]);
36076
- setErrorMessage(t2("Unable to get size recommendation. Please try manual measurements."));
36501
+ setErrorMessage(t2("Unable to get a size suggestion. Please try manual measurements."));
36077
36502
  setEstimationDone(true);
36078
36503
  setSizingLoading(false);
36079
36504
  setView("error");
@@ -36204,7 +36629,7 @@ function PrimeStyleTryonInner({
36204
36629
  } else {
36205
36630
  const errBody = await recRes.text().catch(() => "");
36206
36631
  console.error("[ps-sdk] Sizing recommend failed:", recRes.status, errBody);
36207
- setErrorMessage(t2("Unable to get size recommendation. Please try manual measurements."));
36632
+ setErrorMessage(t2("Unable to get a size suggestion. Please try manual measurements."));
36208
36633
  setEstimationDone(true);
36209
36634
  setSizingLoading(false);
36210
36635
  setView("error");
@@ -36228,6 +36653,13 @@ function PrimeStyleTryonInner({
36228
36653
  const msg = !apiRef.current ? t2("SDK not configured. Please provide an API key.") : t2("Please upload a photo first.");
36229
36654
  setErrorMessage(msg);
36230
36655
  setView("error");
36656
+ reportSdkClientError({
36657
+ message: msg,
36658
+ code: !apiRef.current ? "SDK_NOT_CONFIGURED" : "PHOTO_MISSING",
36659
+ component: "TryOn",
36660
+ view,
36661
+ severity: !apiRef.current ? "high" : "low"
36662
+ });
36231
36663
  onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
36232
36664
  return;
36233
36665
  }
@@ -36385,9 +36817,9 @@ function PrimeStyleTryonInner({
36385
36817
  if (response.modelImageId) modelImageIdRef.current = response.modelImageId;
36386
36818
  onProcessing?.(response.jobId);
36387
36819
  const usePollingOnly = shouldUseShopifyCartAttribution(apiUrl);
36388
- if (!usePollingOnly && response.streamUrl) {
36820
+ if (!usePollingOnly) {
36389
36821
  sseRef.current?.disconnect();
36390
- sseRef.current = new SseClient(response.streamUrl);
36822
+ sseRef.current = new SseClient(response.streamUrl || apiRef.current.getStreamUrl(response.jobId));
36391
36823
  }
36392
36824
  unsubRef.current?.();
36393
36825
  unsubRef.current = usePollingOnly ? null : sseRef.current?.onJob(response.jobId, handleVtoUpdate) ?? null;
@@ -36415,11 +36847,19 @@ function PrimeStyleTryonInner({
36415
36847
  } catch (err) {
36416
36848
  const message = err instanceof Error ? err.message : t2("Failed to start try-on");
36417
36849
  const code = err instanceof PrimeStyleError ? err.code : void 0;
36850
+ reportSdkClientError({
36851
+ message,
36852
+ code: code || "TRYON_SUBMIT_FAILED",
36853
+ stack: err instanceof Error ? err.stack : void 0,
36854
+ component: "TryOn",
36855
+ view,
36856
+ severity: "medium"
36857
+ });
36418
36858
  setErrorMessage(message);
36419
36859
  setView("error");
36420
36860
  onError?.({ message, code });
36421
36861
  }
36422
- }, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, garmentDetailImage, productTitle, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate]);
36862
+ }, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, garmentDetailImage, productTitle, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate, reportSdkClientError, t2, view]);
36423
36863
  reactExports.useEffect(() => {
36424
36864
  if (view !== "size-result") {
36425
36865
  autoTryOnFiredRef.current = false;
@@ -36511,7 +36951,7 @@ function PrimeStyleTryonInner({
36511
36951
  }, [sizingResult]);
36512
36952
  const handleAddToBag = reactExports.useCallback(async () => {
36513
36953
  if (!onAddToBag || !sizingResult) return;
36514
- await onAddToBag({
36954
+ const payload = {
36515
36955
  productId,
36516
36956
  productTitle: restoredProductTitle || productTitle,
36517
36957
  productUrl: restoredProductUrl || effectiveProductUrl,
@@ -36520,7 +36960,33 @@ function PrimeStyleTryonInner({
36520
36960
  resultImageUrl: resultImageUrlRef.current || resultImageUrl,
36521
36961
  historyEntryId: currentHistoryEntryIdRef.current ?? void 0,
36522
36962
  selectedSizes: buildAddToBagSelectedSizes()
36523
- });
36963
+ };
36964
+ try {
36965
+ await onAddToBag(payload);
36966
+ reportSdkEvent("SIZE_RECOMMENDATION_ACCEPTED", {
36967
+ recommendedSize: sizingResult.recommendedSize,
36968
+ metadata: { selectedSizes: payload.selectedSizes }
36969
+ });
36970
+ reportSdkEvent("ADD_TO_CART_FROM_TRYON", {
36971
+ recommendedSize: sizingResult.recommendedSize,
36972
+ metadata: {
36973
+ selectedSizes: payload.selectedSizes,
36974
+ historyEntryId: payload.historyEntryId,
36975
+ hasResult: Boolean(payload.resultImageUrl)
36976
+ }
36977
+ });
36978
+ } catch (error) {
36979
+ reportSdkClientError({
36980
+ message: error instanceof Error ? error.message : "Add to bag failed",
36981
+ code: "ADD_TO_BAG_FAILED",
36982
+ stack: error instanceof Error ? error.stack : void 0,
36983
+ component: "ResultActions",
36984
+ view,
36985
+ severity: "medium",
36986
+ metadata: { selectedSizes: payload.selectedSizes }
36987
+ });
36988
+ throw error;
36989
+ }
36524
36990
  }, [
36525
36991
  buildAddToBagSelectedSizes,
36526
36992
  effectiveProductUrl,
@@ -36530,7 +36996,10 @@ function PrimeStyleTryonInner({
36530
36996
  restoredProductTitle,
36531
36997
  restoredProductUrl,
36532
36998
  resultImageUrl,
36533
- sizingResult
36999
+ reportSdkClientError,
37000
+ reportSdkEvent,
37001
+ sizingResult,
37002
+ view
36534
37003
  ]);
36535
37004
  const handleTryOnFeedbackSubmit = reactExports.useCallback(async ({ rating, note }) => {
36536
37005
  const profileLoggedIn = Boolean(profileSession);
@@ -37195,6 +37664,7 @@ function PrimeStyleTryonInner({
37195
37664
  bodyLandmarks,
37196
37665
  faceLandmarks,
37197
37666
  measurementType: measurementType === "body-basic" ? "body" : measurementType,
37667
+ isAccessoryProduct: measurementType === "body-basic" || measurementType === "face" || measurementType === "head" || measurementType === "wrist",
37198
37668
  activeSection,
37199
37669
  setActiveSection,
37200
37670
  onResetTryOn: () => {
@@ -37739,8 +38209,20 @@ class PrimeStyleTryonErrorBoundary extends reactExports.Component {
37739
38209
  }
37740
38210
  componentDidCatch(error) {
37741
38211
  console.error("[ps-sdk] PrimeStyleTryon render failed:", error);
38212
+ const message = error instanceof Error ? error.message : "PrimeStyleTryon render failed";
38213
+ void new ApiClient(getApiKey(), getApiUrl(this.props.apiUrl)).reportClientError({
38214
+ message,
38215
+ code: "RENDER_ERROR",
38216
+ stack: error instanceof Error ? error.stack : void 0,
38217
+ component: "PrimeStyleTryon",
38218
+ productId: this.props.productId || this.props.productImage,
38219
+ productTitle: this.props.productTitle,
38220
+ productUrl: this.props.productUrl,
38221
+ severity: "high"
38222
+ }).catch(() => {
38223
+ });
37742
38224
  this.props.onError?.({
37743
- message: error instanceof Error ? error.message : "PrimeStyleTryon render failed",
38225
+ message,
37744
38226
  code: "RENDER_ERROR"
37745
38227
  });
37746
38228
  }