@primestyleai/tryon 3.7.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,366 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
- import { useState, useEffect, useRef, useMemo, useCallback } from "react";
4
- import { A as ApiClient, S as SseClient, i as isValidImageFile, c as compressImage, P as PrimeStyleError } from "../image-utils-C9bJ1zKO.js";
3
+ import { useState, useEffect, useMemo, useRef, useCallback } from "react";
4
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage, P as PrimeStyleError } from "../index-B0KE3c8S.js";
5
+ const HEADER_ALIASES = {
6
+ // ── Size label columns (skipped during field derivation) ──
7
+ size: "__size__",
8
+ sizes: "__size__",
9
+ label: "__size__",
10
+ taglia: "__size__",
11
+ // IT
12
+ taille: "__size__",
13
+ // FR
14
+ größe: "__size__",
15
+ // DE
16
+ groesse: "__size__",
17
+ tamaño: "__size__",
18
+ // ES
19
+ サイズ: "__size__",
20
+ // JP
21
+ // ── Chest / Bust ──
22
+ chest: "chest",
23
+ "chest (cm)": "chest",
24
+ "chest(cm)": "chest",
25
+ "chest (in)": "chest",
26
+ bust: "bust",
27
+ "bust (cm)": "bust",
28
+ "bust(cm)": "bust",
29
+ "bust (in)": "bust",
30
+ "chest/bust": "chest",
31
+ "chest / bust": "chest",
32
+ petto: "chest",
33
+ // IT
34
+ poitrine: "bust",
35
+ // FR
36
+ brust: "chest",
37
+ // DE
38
+ // ── Waist ──
39
+ waist: "waist",
40
+ "waist (cm)": "waist",
41
+ "waist(cm)": "waist",
42
+ "waist (in)": "waist",
43
+ vita: "waist",
44
+ // IT
45
+ taille_mesure: "waist",
46
+ // FR (disambiguation from size label)
47
+ "tour de taille": "waist",
48
+ taille_cm: "waist",
49
+ // ── Hips ──
50
+ hips: "hips",
51
+ hip: "hips",
52
+ "hips (cm)": "hips",
53
+ "hip (cm)": "hips",
54
+ "hips(cm)": "hips",
55
+ "hips (in)": "hips",
56
+ fianchi: "hips",
57
+ // IT
58
+ hanches: "hips",
59
+ // FR
60
+ hüfte: "hips",
61
+ // DE
62
+ // ── Shoulder ──
63
+ shoulder: "shoulderWidth",
64
+ shoulders: "shoulderWidth",
65
+ "shoulder width": "shoulderWidth",
66
+ "shoulder (cm)": "shoulderWidth",
67
+ "shoulders (cm)": "shoulderWidth",
68
+ "shoulder width (cm)": "shoulderWidth",
69
+ spalle: "shoulderWidth",
70
+ // IT
71
+ épaules: "shoulderWidth",
72
+ // FR
73
+ schulter: "shoulderWidth",
74
+ // DE
75
+ // ── Sleeve ──
76
+ sleeve: "sleeveLength",
77
+ "sleeve length": "sleeveLength",
78
+ "sleeve (cm)": "sleeveLength",
79
+ "sleeve length (cm)": "sleeveLength",
80
+ manica: "sleeveLength",
81
+ // IT
82
+ manche: "sleeveLength",
83
+ // FR
84
+ ärmel: "sleeveLength",
85
+ // DE
86
+ // ── Inseam ──
87
+ inseam: "inseam",
88
+ "inseam (cm)": "inseam",
89
+ "inseam(cm)": "inseam",
90
+ "inseam (in)": "inseam",
91
+ "inside leg": "inseam",
92
+ "inside leg (cm)": "inseam",
93
+ cavallo: "inseam",
94
+ // IT
95
+ entrejambe: "inseam",
96
+ // FR
97
+ // ── Neck ──
98
+ neck: "neckCircumference",
99
+ collar: "neckCircumference",
100
+ "neck (cm)": "neckCircumference",
101
+ "collar (cm)": "neckCircumference",
102
+ collo: "neckCircumference",
103
+ // IT
104
+ col: "neckCircumference",
105
+ // FR
106
+ // ── Length (body/garment) ──
107
+ length: "length",
108
+ "body length": "length",
109
+ "length (cm)": "length",
110
+ "body length (cm)": "length",
111
+ lunghezza: "length",
112
+ // IT
113
+ longueur: "length",
114
+ // FR
115
+ // ── Thigh ──
116
+ thigh: "thighCircumference",
117
+ "thigh (cm)": "thighCircumference",
118
+ coscia: "thighCircumference",
119
+ // IT
120
+ // ── Foot / Shoe ──
121
+ "foot length": "footLengthCm",
122
+ "foot length (cm)": "footLengthCm",
123
+ "foot (cm)": "footLengthCm",
124
+ cm: "footLengthCm",
125
+ eu: "shoeEU",
126
+ "eu size": "shoeEU",
127
+ eur: "shoeEU",
128
+ us: "shoeUS",
129
+ "us size": "shoeUS",
130
+ uk: "shoeUK",
131
+ "uk size": "shoeUK"
132
+ };
133
+ const FIELD_LABELS = {
134
+ chest: "Chest",
135
+ bust: "Bust",
136
+ waist: "Waist",
137
+ hips: "Hips",
138
+ shoulderWidth: "Shoulders",
139
+ sleeveLength: "Sleeve Length",
140
+ inseam: "Inseam",
141
+ neckCircumference: "Neck",
142
+ length: "Length",
143
+ thighCircumference: "Thigh",
144
+ footLengthCm: "Foot Length",
145
+ shoeEU: "Shoe Size (EU)",
146
+ shoeUS: "Shoe Size (US)",
147
+ shoeUK: "Shoe Size (UK)"
148
+ };
149
+ const FIELD_PLACEHOLDERS = {
150
+ chest: "e.g. 104",
151
+ bust: "e.g. 88",
152
+ waist: "e.g. 84",
153
+ hips: "e.g. 96",
154
+ shoulderWidth: "e.g. 46",
155
+ sleeveLength: "e.g. 64",
156
+ inseam: "e.g. 81",
157
+ neckCircumference: "e.g. 40",
158
+ length: "e.g. 72",
159
+ thighCircumference: "e.g. 58",
160
+ footLengthCm: "e.g. 27",
161
+ shoeEU: "e.g. 42",
162
+ shoeUS: "e.g. 9",
163
+ shoeUK: "e.g. 8"
164
+ };
165
+ const SIZE_LABEL_PATTERN = /^(XXS|XS|S|M|L|XL|XXL|XXXL|2XL|3XL|4XL|5XL|\d{2,3}(\/\d{2,3})?(R|S|L)?|ONE\s*SIZE)$/i;
166
+ const SHOE_FIELD_KEYS = /* @__PURE__ */ new Set(["shoeEU", "shoeUS", "shoeUK", "footLengthCm"]);
167
+ function resolveHeaderKey(header) {
168
+ const cleaned = header.toLowerCase().trim().replace(/\(.*?\)/g, "").trim();
169
+ return HEADER_ALIASES[cleaned] ?? HEADER_ALIASES[header.toLowerCase().trim()] ?? null;
170
+ }
171
+ function deriveRequiredFields(headers) {
172
+ const fields = [];
173
+ const seen = /* @__PURE__ */ new Set();
174
+ for (const h of headers) {
175
+ const fieldKey = resolveHeaderKey(h);
176
+ if (!fieldKey || fieldKey === "__size__" || seen.has(fieldKey)) continue;
177
+ seen.add(fieldKey);
178
+ const isShoe = SHOE_FIELD_KEYS.has(fieldKey);
179
+ fields.push({
180
+ key: fieldKey,
181
+ label: FIELD_LABELS[fieldKey] || h,
182
+ required: true,
183
+ unit: isShoe && fieldKey !== "footLengthCm" ? "size" : "cm",
184
+ placeholder: FIELD_PLACEHOLDERS[fieldKey] || "",
185
+ category: isShoe ? "shoe" : "body"
186
+ });
187
+ }
188
+ fields.sort((a, b) => {
189
+ if (a.category !== b.category) return a.category === "body" ? -1 : 1;
190
+ return 0;
191
+ });
192
+ return fields;
193
+ }
194
+ function isObject(v) {
195
+ return typeof v === "object" && v !== null && !Array.isArray(v);
196
+ }
197
+ function isSizeLabel(key) {
198
+ return SIZE_LABEL_PATTERN.test(key.trim());
199
+ }
200
+ function allKeysAreSizeLabels(obj) {
201
+ const keys = Object.keys(obj);
202
+ if (keys.length === 0) return false;
203
+ return keys.every((k) => isSizeLabel(k));
204
+ }
205
+ function allKeysAreSectionNames(obj) {
206
+ const keys = Object.keys(obj);
207
+ if (keys.length < 2) return false;
208
+ return keys.every((k) => {
209
+ const val = obj[k];
210
+ const isContainer = Array.isArray(val) || isObject(val);
211
+ const isNotSizeLabel = !isSizeLabel(k);
212
+ const isNotMeasurement = !HEADER_ALIASES[k.toLowerCase().trim()];
213
+ return isContainer && isNotSizeLabel && isNotMeasurement;
214
+ });
215
+ }
216
+ function tryPreNormalized(input) {
217
+ if (!isObject(input)) return null;
218
+ const obj = input;
219
+ if (obj.found === true && Array.isArray(obj.headers) && Array.isArray(obj.rows) && obj.headers.length > 0 && obj.rows.length > 0) {
220
+ const headers = obj.headers;
221
+ const rows = obj.rows.map((r) => r.map(String));
222
+ return {
223
+ found: true,
224
+ title: typeof obj.title === "string" ? obj.title : void 0,
225
+ headers,
226
+ rows,
227
+ requiredFields: Array.isArray(obj.requiredFields) && obj.requiredFields.length > 0 ? obj.requiredFields : deriveRequiredFields(headers)
228
+ };
229
+ }
230
+ return null;
231
+ }
232
+ function tryKeyValueObject(input) {
233
+ if (!isObject(input)) return null;
234
+ const obj = input;
235
+ if (!allKeysAreSizeLabels(obj)) return null;
236
+ const sizeLabels = Object.keys(obj);
237
+ const firstVal = obj[sizeLabels[0]];
238
+ if (!isObject(firstVal)) return null;
239
+ const measureKeySet = /* @__PURE__ */ new Set();
240
+ for (const label of sizeLabels) {
241
+ const sizeObj = obj[label];
242
+ if (!isObject(sizeObj)) return null;
243
+ for (const k of Object.keys(sizeObj)) {
244
+ measureKeySet.add(k);
245
+ }
246
+ }
247
+ const measureKeys = Array.from(measureKeySet);
248
+ const headers = ["Size", ...measureKeys];
249
+ const rows = sizeLabels.map((label) => {
250
+ const sizeObj = obj[label];
251
+ return [label, ...measureKeys.map((k) => String(sizeObj[k] ?? ""))];
252
+ });
253
+ return { found: true, headers, rows, requiredFields: deriveRequiredFields(headers) };
254
+ }
255
+ function tryArrayOfObjects(input) {
256
+ if (!Array.isArray(input) || input.length === 0) return null;
257
+ if (!isObject(input[0])) return null;
258
+ const first = input[0];
259
+ const sizeKey = Object.keys(first).find((k) => {
260
+ const alias = HEADER_ALIASES[k.toLowerCase().trim()];
261
+ return alias === "__size__";
262
+ }) || Object.keys(first).find((k) => k.toLowerCase() === "size" || k.toLowerCase() === "label");
263
+ if (!sizeKey) return null;
264
+ const allKeys = /* @__PURE__ */ new Set();
265
+ for (const row of input) {
266
+ if (!isObject(row)) return null;
267
+ for (const k of Object.keys(row)) {
268
+ allKeys.add(k);
269
+ }
270
+ }
271
+ const measureKeys = Array.from(allKeys).filter((k) => k !== sizeKey);
272
+ const headers = [sizeKey, ...measureKeys];
273
+ const rows = input.map((row) => {
274
+ const obj = row;
275
+ return headers.map((h) => String(obj[h] ?? ""));
276
+ });
277
+ const displayHeaders = headers.map((h) => h.charAt(0).toUpperCase() + h.slice(1));
278
+ return { found: true, headers: displayHeaders, rows, requiredFields: deriveRequiredFields(displayHeaders) };
279
+ }
280
+ function tryArrayOfArrays(input) {
281
+ if (!Array.isArray(input) || input.length < 2) return null;
282
+ if (!Array.isArray(input[0])) return null;
283
+ const headers = input[0].map(String);
284
+ const rows = input.slice(1).map((r) => r.map(String));
285
+ if (headers.length < 2) return null;
286
+ return { found: true, headers, rows, requiredFields: deriveRequiredFields(headers) };
287
+ }
288
+ function tryWrapperObject(input) {
289
+ if (!isObject(input)) return null;
290
+ const obj = input;
291
+ const arrayKey = ["sizes", "data", "sizeChart", "size_chart", "sizeGuide", "size_guide", "chart"].find(
292
+ (k) => Array.isArray(obj[k])
293
+ );
294
+ if (!arrayKey) return null;
295
+ const inner = obj[arrayKey];
296
+ return tryArrayOfObjects(inner) ?? tryArrayOfArrays(inner);
297
+ }
298
+ function tryMultiSection(input) {
299
+ if (!isObject(input)) return null;
300
+ const obj = input;
301
+ if (!allKeysAreSectionNames(obj)) return null;
302
+ const sections = {};
303
+ let primaryHeaders = [];
304
+ let primaryRows = [];
305
+ const allFieldKeys = /* @__PURE__ */ new Set();
306
+ const allFields = [];
307
+ for (const [sectionName, sectionData] of Object.entries(obj)) {
308
+ const normalized = tryArrayOfObjects(sectionData) ?? tryArrayOfArrays(sectionData) ?? tryKeyValueObject(sectionData) ?? tryWrapperObject(sectionData);
309
+ if (!normalized) return null;
310
+ sections[sectionName] = {
311
+ headers: normalized.headers,
312
+ rows: normalized.rows,
313
+ requiredFields: normalized.requiredFields
314
+ };
315
+ if (primaryHeaders.length === 0) {
316
+ primaryHeaders = normalized.headers;
317
+ primaryRows = normalized.rows;
318
+ }
319
+ for (const f of normalized.requiredFields) {
320
+ if (!allFieldKeys.has(f.key)) {
321
+ allFieldKeys.add(f.key);
322
+ allFields.push(f);
323
+ }
324
+ }
325
+ }
326
+ if (Object.keys(sections).length === 0) return null;
327
+ return {
328
+ found: true,
329
+ headers: primaryHeaders,
330
+ rows: primaryRows,
331
+ requiredFields: allFields,
332
+ sections
333
+ };
334
+ }
335
+ function tryJsonString(input) {
336
+ if (typeof input !== "string") return null;
337
+ const trimmed = input.trim();
338
+ if (trimmed.startsWith("<") || trimmed.includes("<table") || trimmed.includes("<tr")) {
339
+ return null;
340
+ }
341
+ try {
342
+ const parsed = JSON.parse(trimmed);
343
+ return normalizeSizeGuide(parsed).success ? normalizeSizeGuide(parsed).data : null;
344
+ } catch {
345
+ return null;
346
+ }
347
+ }
348
+ function normalizeSizeGuide(input) {
349
+ if (input === null || input === void 0) {
350
+ return { success: false, reason: "no data provided" };
351
+ }
352
+ const result = tryPreNormalized(input) ?? tryMultiSection(input) ?? tryKeyValueObject(input) ?? tryArrayOfObjects(input) ?? tryArrayOfArrays(input) ?? tryWrapperObject(input) ?? tryJsonString(input);
353
+ if (result && result.requiredFields.length > 0) {
354
+ return { success: true, data: result };
355
+ }
356
+ if (result && result.requiredFields.length === 0 && result.rows.length > 0) {
357
+ return { success: true, data: result };
358
+ }
359
+ return {
360
+ success: false,
361
+ reason: typeof input === "string" ? "unstructured string" : "unrecognised format"
362
+ };
363
+ }
5
364
  function cx(base, override) {
6
365
  return override ? `${base} ${override}` : base;
7
366
  }
@@ -51,8 +410,8 @@ const SIZING_COUNTRIES = [
51
410
  { code: "AU", label: "Australia" },
52
411
  { code: "BR", label: "Brazil" }
53
412
  ];
54
- const STEP_LABELS = ["", "Welcome", "Photo", "Size", "Generate", "Results"];
55
- const TOTAL_STEPS = 5;
413
+ const STEP_LABELS = ["", "Welcome", "Size", "Your Fit", "Try On"];
414
+ const TOTAL_STEPS = 4;
56
415
  function detectLocale() {
57
416
  if (typeof window === "undefined") return "US";
58
417
  const l = (navigator.language || "en-US").toLowerCase();
@@ -78,22 +437,6 @@ function lbsToKg(lbs) {
78
437
  function ftInToCm(ft, inch) {
79
438
  return +(ft * 30.48 + inch * 2.54).toFixed(1);
80
439
  }
81
- function SvgIcon({ d, size = 18, strokeWidth = 2 }) {
82
- return /* @__PURE__ */ jsx(
83
- "svg",
84
- {
85
- width: size,
86
- height: size,
87
- viewBox: "0 0 24 24",
88
- fill: "none",
89
- stroke: "currentColor",
90
- strokeWidth,
91
- strokeLinecap: "round",
92
- strokeLinejoin: "round",
93
- children: /* @__PURE__ */ jsx("path", { d })
94
- }
95
- );
96
- }
97
440
  function CameraIcon({ size = 18 }) {
98
441
  return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
99
442
  /* @__PURE__ */ jsx("path", { d: "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" }),
@@ -181,11 +524,12 @@ function PrimeStyleTryon(props) {
181
524
  function PrimeStyleTryonInner({
182
525
  productImage,
183
526
  productTitle = "Product",
184
- buttonText = "Virtual Try-On",
527
+ buttonText,
185
528
  apiUrl,
186
529
  showPoweredBy = true,
187
530
  showIcon = true,
188
531
  buttonIcon,
532
+ locale,
189
533
  buttonStyles: btnS = {},
190
534
  modalStyles: mdlS = {},
191
535
  classNames: cn = {},
@@ -199,6 +543,8 @@ function PrimeStyleTryonInner({
199
543
  onError,
200
544
  sizeGuideData
201
545
  }) {
546
+ const t = useMemo(() => createT(locale), [locale]);
547
+ const resolvedButtonText = buttonText ?? t("Virtual Try-On");
202
548
  const [view, setView] = useState("idle");
203
549
  const [selectedFile, setSelectedFile] = useState(null);
204
550
  const [previewUrl, setPreviewUrl] = useState(null);
@@ -267,12 +613,12 @@ function PrimeStyleTryonInner({
267
613
  if (progressIntervalRef.current) return;
268
614
  progressRef.current = 0;
269
615
  const statuses = [
270
- { at: 0, text: "Preparing your image..." },
271
- { at: 15, text: "Analyzing body proportions..." },
272
- { at: 30, text: "Matching garment to your photo..." },
273
- { at: 50, text: "Generating virtual try-on..." },
274
- { at: 75, text: "Refining details..." },
275
- { at: 90, text: "Almost there..." }
616
+ { at: 0, text: t("Preparing your image...") },
617
+ { at: 15, text: t("Analyzing body proportions...") },
618
+ { at: 30, text: t("Matching garment to your photo...") },
619
+ { at: 50, text: t("Generating virtual try-on...") },
620
+ { at: 75, text: t("Refining details...") },
621
+ { at: 90, text: t("Almost there...") }
276
622
  ];
277
623
  progressIntervalRef.current = setInterval(() => {
278
624
  const p = progressRef.current;
@@ -327,13 +673,25 @@ function PrimeStyleTryonInner({
327
673
  useEffect(() => {
328
674
  lsSet("history", history);
329
675
  }, [history]);
676
+ const normalizedGuide = useMemo(() => {
677
+ if (!sizeGuideData) return null;
678
+ return normalizeSizeGuide(sizeGuideData);
679
+ }, [sizeGuideData]);
330
680
  useEffect(() => {
331
- if (view !== "sizing-choice" || sizeGuideFetchedRef.current || !apiRef.current) return;
681
+ if (view !== "sizing-choice" || sizeGuideFetchedRef.current) return;
332
682
  sizeGuideFetchedRef.current = true;
333
683
  if (!sizeGuideData) {
334
684
  setSizeGuide({ found: false });
335
685
  return;
336
686
  }
687
+ if (normalizedGuide?.success) {
688
+ setSizeGuide(normalizedGuide.data);
689
+ return;
690
+ }
691
+ if (!apiRef.current) {
692
+ setSizeGuide({ found: false });
693
+ return;
694
+ }
337
695
  setSizeGuideFetching(true);
338
696
  const baseUrl = getApiUrl(apiUrl);
339
697
  const key = getApiKey();
@@ -345,20 +703,20 @@ function PrimeStyleTryonInner({
345
703
  if (data) setSizeGuide(data);
346
704
  else setSizeGuide({ found: false });
347
705
  }).catch(() => setSizeGuide({ found: false })).finally(() => setSizeGuideFetching(false));
348
- }, [view, apiUrl, productTitle, sizeGuideData]);
706
+ }, [view, apiUrl, productTitle, sizeGuideData, normalizedGuide]);
349
707
  const stepIndex = useMemo(() => {
350
708
  switch (view) {
351
709
  case "welcome":
352
710
  return 1;
353
- case "upload":
354
- return 2;
355
711
  case "sizing-choice":
356
712
  case "sizing-form":
713
+ return 2;
714
+ case "size-result":
357
715
  return 3;
716
+ case "upload":
358
717
  case "processing":
359
- return 4;
360
718
  case "result":
361
- return 5;
719
+ return 4;
362
720
  default:
363
721
  return 1;
364
722
  }
@@ -385,6 +743,7 @@ function PrimeStyleTryonInner({
385
743
  setFormGender("male");
386
744
  sizeGuideFetchedRef.current = false;
387
745
  setSizeGuideFetching(false);
746
+ historySavedRef.current = false;
388
747
  unsubRef.current?.();
389
748
  unsubRef.current = null;
390
749
  if (pollingRef.current) {
@@ -395,13 +754,13 @@ function PrimeStyleTryonInner({
395
754
  }, [onClose, previewUrl]);
396
755
  const handleFileSelect = useCallback((file) => {
397
756
  if (!isValidImageFile(file)) {
398
- setErrorMessage("Please upload a JPEG, PNG, or WebP image.");
757
+ setErrorMessage(t("Please upload a JPEG, PNG, or WebP image."));
399
758
  setView("error");
400
759
  onError?.({ message: "Invalid file type", code: "INVALID_FILE" });
401
760
  return;
402
761
  }
403
762
  if (file.size > 10 * 1024 * 1024) {
404
- setErrorMessage("Image must be under 10MB.");
763
+ setErrorMessage(t("Image must be under 10MB."));
405
764
  setView("error");
406
765
  onError?.({ message: "File too large", code: "FILE_TOO_LARGE" });
407
766
  return;
@@ -435,7 +794,7 @@ function PrimeStyleTryonInner({
435
794
  progressRef.current = 100;
436
795
  if (progressBarRef.current) progressBarRef.current.style.width = "100%";
437
796
  if (progressTextRef.current) progressTextRef.current.textContent = "100%";
438
- if (progressStatusRef.current) progressStatusRef.current.textContent = "Complete!";
797
+ if (progressStatusRef.current) progressStatusRef.current.textContent = t("Complete!");
439
798
  cleanupJob();
440
799
  setTimeout(() => setView("result"), 400);
441
800
  onComplete?.({ jobId: update.galleryId, imageUrl: update.imageUrl });
@@ -444,7 +803,7 @@ function PrimeStyleTryonInner({
444
803
  if (!completedRef.current) {
445
804
  completedRef.current = true;
446
805
  cleanupJob();
447
- const msg = update.error || "Try-on generation failed";
806
+ const msg = update.error || t("Try-on generation failed");
448
807
  setErrorMessage(msg);
449
808
  setView("error");
450
809
  onError?.({ message: msg });
@@ -466,7 +825,10 @@ function PrimeStyleTryonInner({
466
825
  locale: sizingCountry,
467
826
  product: { title: productTitle, description: "", variants: [] }
468
827
  };
469
- if (sizeGuide?.found) payload.sizeGuide = sizeGuide;
828
+ if (sizeGuide?.found) {
829
+ payload.sizeGuide = sizeGuide;
830
+ if (sizeGuide.sections) payload.sizeGuide = { ...sizeGuide, sections: sizeGuide.sections };
831
+ }
470
832
  payload.sizingUnit = sizingUnit;
471
833
  if (sizingMethod === "exact") {
472
834
  const m = { gender: formRef.current.gender || "male", sizingUnit };
@@ -514,9 +876,9 @@ function PrimeStyleTryonInner({
514
876
  setSizingLoading(false);
515
877
  }
516
878
  }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields]);
517
- const handleSubmit = useCallback(async () => {
879
+ const handleTryOnSubmit = useCallback(async () => {
518
880
  if (!selectedFile || !apiRef.current || !sseRef.current) {
519
- const msg = !apiRef.current ? "Missing NEXT_PUBLIC_PRIMESTYLE_API_KEY" : "No file selected";
881
+ const msg = !apiRef.current ? t("SDK not configured. Please provide an API key.") : t("Something went wrong");
520
882
  setErrorMessage(msg);
521
883
  setView("error");
522
884
  onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
@@ -524,10 +886,6 @@ function PrimeStyleTryonInner({
524
886
  }
525
887
  completedRef.current = false;
526
888
  setView("processing");
527
- if (sizingMethod) {
528
- setSizingLoading(true);
529
- submitSizing();
530
- }
531
889
  try {
532
890
  const modelImage = await compressImage(selectedFile);
533
891
  const response = await apiRef.current.submitTryOn(modelImage, productImage);
@@ -555,13 +913,13 @@ function PrimeStyleTryonInner({
555
913
  }
556
914
  }, 3e3);
557
915
  } catch (err) {
558
- const message = err instanceof Error ? err.message : "Failed to start try-on";
916
+ const message = err instanceof Error ? err.message : t("Failed to start try-on");
559
917
  const code = err instanceof PrimeStyleError ? err.code : void 0;
560
918
  setErrorMessage(message);
561
919
  setView("error");
562
920
  onError?.({ message, code });
563
921
  }
564
- }, [selectedFile, productImage, onProcessing, onError, handleVtoUpdate, sizingMethod, submitSizing]);
922
+ }, [selectedFile, productImage, onProcessing, onError, handleVtoUpdate]);
565
923
  const handleDownload = useCallback(() => {
566
924
  if (!resultImageUrl) return;
567
925
  if (resultImageUrl.startsWith("data:")) {
@@ -592,7 +950,7 @@ function PrimeStyleTryonInner({
592
950
  setSizingResult(null);
593
951
  setSizingLoading(false);
594
952
  setProfileSaved(false);
595
- setView("upload");
953
+ setView("sizing-choice");
596
954
  }, [previewUrl, cleanupJob]);
597
955
  const applyProfile = useCallback((id) => {
598
956
  const p = profiles.find((pr) => pr.id === id);
@@ -712,22 +1070,30 @@ function PrimeStyleTryonInner({
712
1070
  }
713
1071
  setHistory((prev) => [entry, ...prev].slice(0, 50));
714
1072
  }, [productTitle, productImage, resultImageUrl, sizingResult, activeProfileId, profiles]);
1073
+ const historySavedRef = useRef(false);
715
1074
  useEffect(() => {
716
- if (view === "result" && (resultImageUrl || sizingResult)) {
1075
+ if (view === "size-result" && sizingResult && !historySavedRef.current) {
1076
+ historySavedRef.current = true;
1077
+ saveHistoryEntry();
1078
+ } else if (view === "result" && resultImageUrl && !historySavedRef.current) {
1079
+ historySavedRef.current = true;
717
1080
  saveHistoryEntry();
1081
+ } else if (view === "welcome" || view === "sizing-choice") {
1082
+ historySavedRef.current = false;
718
1083
  }
719
- }, [view]);
1084
+ }, [view, sizingResult, resultImageUrl]);
720
1085
  const updateField = useCallback((key, val) => {
721
1086
  formRef.current[key] = val;
722
1087
  }, []);
723
1088
  const shoeField = useMemo(() => {
724
1089
  const map = {
725
- US: { key: "shoeUS", label: "Shoe size (US)", ph: "e.g. 10" },
726
- UK: { key: "shoeUK", label: "Shoe size (UK)", ph: "e.g. 9" },
727
- AU: { key: "shoeUK", label: "Shoe size (UK)", ph: "e.g. 9" }
1090
+ US: { key: "shoeUS", labelKey: "Shoe size (US)", ph: "e.g. 10" },
1091
+ UK: { key: "shoeUK", labelKey: "Shoe size (UK)", ph: "e.g. 9" },
1092
+ AU: { key: "shoeUK", labelKey: "Shoe size (UK)", ph: "e.g. 9" }
728
1093
  };
729
- return map[sizingCountry] || { key: "shoeEU", label: "Shoe size (EU)", ph: "e.g. 43" };
730
- }, [sizingCountry]);
1094
+ const raw = map[sizingCountry] || { key: "shoeEU", labelKey: "Shoe size (EU)", ph: "e.g. 43" };
1095
+ return { key: raw.key, label: t(raw.labelKey), ph: raw.ph };
1096
+ }, [sizingCountry, t]);
731
1097
  const rootVars = {
732
1098
  "--ps-btn-bg": btnS.backgroundColor,
733
1099
  "--ps-btn-color": btnS.textColor,
@@ -771,7 +1137,7 @@ function PrimeStyleTryonInner({
771
1137
  i > 1 && /* @__PURE__ */ jsx("div", { className: `ps-tryon-stepper-line${i <= stepIndex ? " ps-done" : ""}` }),
772
1138
  /* @__PURE__ */ jsxs("div", { className: `ps-tryon-stepper-step${i < stepIndex ? " ps-done" : i === stepIndex ? " ps-active" : ""}`, children: [
773
1139
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-stepper-circle", children: i < stepIndex ? /* @__PURE__ */ jsx(CheckIcon, {}) : i }),
774
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-stepper-label", children: STEP_LABELS[i] })
1140
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-stepper-label", children: t(STEP_LABELS[i]) })
775
1141
  ] })
776
1142
  ] }, i)) }) });
777
1143
  }
@@ -800,34 +1166,35 @@ function PrimeStyleTryonInner({
800
1166
  /* @__PURE__ */ jsx("img", { src: productImage, alt: "Product", className: "ps-tryon-welcome-product" }),
801
1167
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-welcome-sparkle", children: /* @__PURE__ */ jsx(SparkleIcon, { size: 20 }) })
802
1168
  ] }),
803
- /* @__PURE__ */ jsx("h2", { className: "ps-tryon-welcome-title", children: "See How It Looks On You" }),
804
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-welcome-sub", children: "Virtual try-on + AI size recommendation" })
1169
+ /* @__PURE__ */ jsx("h2", { className: "ps-tryon-welcome-title", children: t("Find Your Perfect Size") }),
1170
+ /* @__PURE__ */ jsx("p", { className: "ps-tryon-welcome-sub", children: t("Get your size instantly, then try it on") })
805
1171
  ] }),
806
1172
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-features", children: [
807
- { icon: /* @__PURE__ */ jsx(CameraIcon, {}), title: "Upload Photo", desc: "Share a photo of yourself" },
808
- { icon: /* @__PURE__ */ jsx(RulerIcon, {}), title: "Find Your Size", desc: "AI-powered fit analysis" },
809
- { icon: /* @__PURE__ */ jsx(SparkleIcon, {}), title: "See Results", desc: "Try-on in seconds" }
1173
+ { icon: /* @__PURE__ */ jsx(RulerIcon, {}), title: t("Get Your Size"), desc: t("Instant fit recommendation") },
1174
+ { icon: /* @__PURE__ */ jsx(CameraIcon, {}), title: t("Try It On"), desc: t("See how it looks on you") }
810
1175
  ].map((f, i) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-feature", children: [
811
1176
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-feature-icon", children: f.icon }),
812
1177
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-feature-title", children: f.title }),
813
1178
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-feature-desc", children: f.desc })
814
1179
  ] }, i)) }),
815
- /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("upload"), children: [
816
- "Let’s Get Started ",
1180
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("sizing-choice"), children: [
1181
+ t("Find My Size"),
1182
+ " ",
817
1183
  /* @__PURE__ */ jsx(ArrowRightIcon, {})
818
1184
  ] }),
819
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-welcome-note", children: "Takes less than a minute" })
1185
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-welcome-note", children: t("Takes less than a minute") })
820
1186
  ] });
821
1187
  }
822
1188
  function UploadView() {
823
1189
  return /* @__PURE__ */ jsx(Fragment, { children: selectedFile && previewUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
824
1190
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-preview", cn.preview), children: [
825
1191
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-preview-blur", style: { backgroundImage: `url(${previewUrl})` } }),
826
- /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo", className: cn.previewImage }),
1192
+ /* @__PURE__ */ jsx("img", { src: previewUrl, alt: t("Your photo"), className: cn.previewImage }),
827
1193
  /* @__PURE__ */ jsx("button", { onClick: handleRemovePreview, className: cx("ps-tryon-preview-remove", cn.removeButton), children: "×" })
828
1194
  ] }),
829
- /* @__PURE__ */ jsxs("button", { onClick: () => setView("sizing-choice"), className: cx("ps-tryon-submit", cn.submitButton), children: [
830
- "Continue to Sizing ",
1195
+ /* @__PURE__ */ jsxs("button", { onClick: handleTryOnSubmit, className: cx("ps-tryon-submit", cn.submitButton), children: [
1196
+ t("Try It On"),
1197
+ " ",
831
1198
  /* @__PURE__ */ jsx(ArrowRightIcon, {})
832
1199
  ] })
833
1200
  ] }) : /* @__PURE__ */ jsxs(
@@ -861,8 +1228,8 @@ function PrimeStyleTryonInner({
861
1228
  }
862
1229
  ),
863
1230
  /* @__PURE__ */ jsx(UploadIcon, {}),
864
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-text", cn.uploadText), children: "Drop or upload your full body photo!" }),
865
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-hint", cn.uploadHint), children: "JPEG, PNG or WebP (max 10MB)" })
1231
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-text", cn.uploadText), children: t("Upload a full body photo") }),
1232
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-upload-hint", cn.uploadHint), children: t("JPEG, PNG or WebP (max 10MB)") })
866
1233
  ]
867
1234
  }
868
1235
  ) });
@@ -874,16 +1241,17 @@ function PrimeStyleTryonInner({
874
1241
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-sizing-choice", children: /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sg-checking", children: [
875
1242
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-checking-icon", children: /* @__PURE__ */ jsx(RulerIcon, { size: 32 }) }),
876
1243
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-checking-bar-wrap", children: /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-checking-bar" }) }),
877
- /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: "Checking size guide..." }),
878
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-sg-checking-sub", children: "Looking for size chart data for this product" })
1244
+ /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: t("Checking size guide...") }),
1245
+ /* @__PURE__ */ jsx("p", { className: "ps-tryon-sg-checking-sub", children: t("Looking for size chart data for this product") })
879
1246
  ] }) });
880
1247
  }
881
1248
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sizing-choice", children: [
882
- /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: "How would you like to find your size?" }),
883
- sgChecked && !sgAvailable && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-notice", children: "Size guide is not available for this product — sizing will use standard measurements" }),
1249
+ /* @__PURE__ */ jsx("h3", { className: "ps-tryon-section-title", children: t("How would you like to find your size?") }),
1250
+ sgChecked && !sgAvailable && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sg-notice", children: t("Size guide is not available for this product — sizing will use standard measurements") }),
884
1251
  sgChecked && sgAvailable && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sg-notice ps-tryon-sg-found", children: [
885
1252
  /* @__PURE__ */ jsx(CheckIcon, { size: 14 }),
886
- " Size guide found for this product"
1253
+ " ",
1254
+ t("Size guide found for this product")
887
1255
  ] }),
888
1256
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-choice-cards", children: [
889
1257
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-choice-card", onClick: () => {
@@ -892,10 +1260,10 @@ function PrimeStyleTryonInner({
892
1260
  }, children: [
893
1261
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-icon", children: /* @__PURE__ */ jsx(RulerIcon, { size: 24 }) }),
894
1262
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-choice-info", children: [
895
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: "Enter my measurements" }),
896
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: sizeGuide?.requiredFields?.length ? sizeGuide.requiredFields.filter((f) => f.required).slice(0, 3).map((f) => f.label).join(", ") + (sizeGuide.requiredFields.length > 3 ? " & more" : "") : "Chest, waist, hips, shoes & more" })
1263
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: t("Enter my measurements") }),
1264
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: sizeGuide?.requiredFields?.length ? sizeGuide.requiredFields.filter((f) => f.required).slice(0, 3).map((f) => t(f.label)).join(", ") + (sizeGuide.requiredFields.length > 3 ? ` ${t("& more")}` : "") : t("Chest, waist, hips, shoes & more") })
897
1265
  ] }),
898
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-choice-badge", children: "Best accuracy" })
1266
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-choice-badge", children: t("Best accuracy") })
899
1267
  ] }),
900
1268
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-choice-card", onClick: () => {
901
1269
  setSizingMethod("quick");
@@ -903,18 +1271,18 @@ function PrimeStyleTryonInner({
903
1271
  }, children: [
904
1272
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-icon", children: /* @__PURE__ */ jsx(SparkleIcon, { size: 24 }) }),
905
1273
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-choice-info", children: [
906
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: "Just height & weight" }),
907
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: "Quick estimate in seconds" })
1274
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: t("Just height & weight") }),
1275
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: t("Quick estimate in seconds") })
908
1276
  ] })
909
1277
  ] }),
910
1278
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-choice-card", onClick: () => {
911
1279
  setSizingMethod(null);
912
- handleSubmit();
1280
+ setView("upload");
913
1281
  }, children: [
914
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-icon", children: /* @__PURE__ */ jsx(SvgIcon, { d: "M13 5H1M13 9H1M13 13H1M5 17l4 4 8-8", size: 24, strokeWidth: 1.5 }) }),
1282
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-icon", children: /* @__PURE__ */ jsx(CameraIcon, { size: 24 }) }),
915
1283
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-choice-info", children: [
916
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: "Skip sizing" }),
917
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: "Just show me the try-on" })
1284
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-title", children: t("Skip, just try it on") }),
1285
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-choice-desc", children: t("Upload a photo to see how it looks") })
918
1286
  ] })
919
1287
  ] })
920
1288
  ] })
@@ -928,37 +1296,38 @@ function PrimeStyleTryonInner({
928
1296
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sizing-form", children: [
929
1297
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-back", onClick: () => setView("sizing-choice"), children: [
930
1298
  /* @__PURE__ */ jsx(ArrowLeftIcon, {}),
931
- " Back"
1299
+ " ",
1300
+ t("Back")
932
1301
  ] }),
933
1302
  sizingMethod === "exact" && profiles.length > 0 && /* @__PURE__ */ jsx("div", { className: "ps-tryon-profile-bar", children: /* @__PURE__ */ jsxs("select", { className: "ps-tryon-profile-select", value: activeProfileId || "", onChange: (e) => {
934
1303
  if (e.target.value) applyProfile(e.target.value);
935
1304
  }, children: [
936
- /* @__PURE__ */ jsx("option", { value: "", children: "Auto-fill from saved profile..." }),
1305
+ /* @__PURE__ */ jsx("option", { value: "", children: t("Auto-fill from saved profile...") }),
937
1306
  profiles.map((p) => /* @__PURE__ */ jsxs("option", { value: p.id, children: [
938
1307
  p.name,
939
1308
  " (",
940
- p.gender === "female" ? "Women's" : "Men's",
1309
+ p.gender === "female" ? t("Women's") : t("Men's"),
941
1310
  ")"
942
1311
  ] }, p.id))
943
1312
  ] }) }),
944
1313
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
945
- /* @__PURE__ */ jsx("label", { children: "I'm shopping for" }),
1314
+ /* @__PURE__ */ jsx("label", { children: t("I'm shopping for") }),
946
1315
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-unit-toggle", children: [
947
1316
  /* @__PURE__ */ jsx("button", { className: `ps-tryon-unit-btn${!isFemale ? " ps-active" : ""}`, onClick: () => {
948
1317
  updateField("gender", "male");
949
1318
  setFormGender("male");
950
- }, children: "Men's" }),
1319
+ }, children: t("Men's") }),
951
1320
  /* @__PURE__ */ jsx("button", { className: `ps-tryon-unit-btn${isFemale ? " ps-active" : ""}`, onClick: () => {
952
1321
  updateField("gender", "female");
953
1322
  setFormGender("female");
954
- }, children: "Women's" })
1323
+ }, children: t("Women's") })
955
1324
  ] })
956
1325
  ] }),
957
1326
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
958
- /* @__PURE__ */ jsx("label", { children: "Sizing region" }),
959
- /* @__PURE__ */ jsx("select", { className: "ps-tryon-country-select", value: sizingCountry, onChange: (e) => setSizingCountry(e.target.value), children: SIZING_COUNTRIES.map((c) => /* @__PURE__ */ jsx("option", { value: c.code, children: c.label }, c.code)) })
1327
+ /* @__PURE__ */ jsx("label", { children: t("Sizing region") }),
1328
+ /* @__PURE__ */ jsx("select", { className: "ps-tryon-country-select", value: sizingCountry, onChange: (e) => setSizingCountry(e.target.value), children: SIZING_COUNTRIES.map((c) => /* @__PURE__ */ jsx("option", { value: c.code, children: t(c.label) }, c.code)) })
960
1329
  ] }),
961
- sizingMethod === "exact" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: "cm", value: "cm" }, { label: "in", value: "in" }], value: sizingUnit, onChange: (v) => {
1330
+ sizingMethod === "exact" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: t("cm"), value: "cm" }, { label: t("in"), value: "in" }], value: sizingUnit, onChange: (v) => {
962
1331
  setSizingUnit(v);
963
1332
  setHeightUnit(v === "cm" ? "cm" : "ft");
964
1333
  setWeightUnit(v === "cm" ? "kg" : "lbs");
@@ -975,7 +1344,7 @@ function PrimeStyleTryonInner({
975
1344
  const showOriginal = field.key !== key;
976
1345
  return /* @__PURE__ */ jsxs("span", { children: [
977
1346
  /* @__PURE__ */ jsx(InputRow, { label: `${regionField.label}${field.required ? " *" : ""}`, fieldKey: key, placeholder: regionField.ph }),
978
- showOriginal && /* @__PURE__ */ jsx(InputRow, { label: field.label, fieldKey: field.key, placeholder: field.placeholder })
1347
+ showOriginal && /* @__PURE__ */ jsx(InputRow, { label: t(field.label), fieldKey: field.key, placeholder: field.placeholder })
979
1348
  ] }, field.key);
980
1349
  }
981
1350
  const phNum = parseFloat(field.placeholder?.replace(/[^0-9.]/g, "") || "");
@@ -984,7 +1353,7 @@ function PrimeStyleTryonInner({
984
1353
  return /* @__PURE__ */ jsx(
985
1354
  InputRow,
986
1355
  {
987
- label: `${field.label}${field.required ? " *" : ""}`,
1356
+ label: `${t(field.label)}${field.required ? " *" : ""}`,
988
1357
  fieldKey: field.key,
989
1358
  placeholder,
990
1359
  type: "number",
@@ -1009,11 +1378,11 @@ function PrimeStyleTryonInner({
1009
1378
  const allOptFields = [...optFields, ...profileExtras];
1010
1379
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1011
1380
  reqFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1012
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-section-label", children: "Required for this product" }),
1381
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-section-label", children: t("Required for this product") }),
1013
1382
  reqFields.map(renderField)
1014
1383
  ] }),
1015
1384
  isFemale && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
1016
- /* @__PURE__ */ jsx("label", { children: "Fit type" }),
1385
+ /* @__PURE__ */ jsx("label", { children: t("Fit type") }),
1017
1386
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-unit-toggle", children: ["petite", "standard", "tall", "plus"].map((fp) => /* @__PURE__ */ jsx(
1018
1387
  "button",
1019
1388
  {
@@ -1021,9 +1390,10 @@ function PrimeStyleTryonInner({
1021
1390
  onClick: (e) => {
1022
1391
  updateField("fitPreference", fp);
1023
1392
  const btns = e.target.parentElement.querySelectorAll(".ps-tryon-unit-btn");
1024
- btns.forEach((b) => b.classList.toggle("ps-active", b.textContent?.toLowerCase() === fp));
1393
+ btns.forEach((b) => b.classList.toggle("ps-active", b.dataset.fp === fp));
1025
1394
  },
1026
- children: fp.charAt(0).toUpperCase() + fp.slice(1)
1395
+ "data-fp": fp,
1396
+ children: t(fp.charAt(0).toUpperCase() + fp.slice(1))
1027
1397
  },
1028
1398
  fp
1029
1399
  )) })
@@ -1038,7 +1408,7 @@ function PrimeStyleTryonInner({
1038
1408
  if (arrow) arrow.style.transform = open ? "rotate(0deg)" : "rotate(180deg)";
1039
1409
  }
1040
1410
  }, children: [
1041
- /* @__PURE__ */ jsx("span", { children: "Optional — improve accuracy & save to profile" }),
1411
+ /* @__PURE__ */ jsx("span", { children: t("Optional — improve accuracy & save to profile") }),
1042
1412
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-chevron", children: "▾" })
1043
1413
  ] }),
1044
1414
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-optional-fields", style: { display: "none" }, children: allOptFields.map(renderField) })
@@ -1046,33 +1416,39 @@ function PrimeStyleTryonInner({
1046
1416
  ] });
1047
1417
  })() }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1048
1418
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
1049
- /* @__PURE__ */ jsx("label", { children: "Height *" }),
1419
+ /* @__PURE__ */ jsxs("label", { children: [
1420
+ t("Height"),
1421
+ " *"
1422
+ ] }),
1050
1423
  heightUnit === "ft" ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-height-ft", children: [
1051
1424
  /* @__PURE__ */ jsx("input", { type: "number", placeholder: "5", defaultValue: formRef.current.heightFeet || "", onInput: (e) => updateField("heightFeet", e.target.value) }),
1052
- /* @__PURE__ */ jsx("span", { children: "ft" }),
1425
+ /* @__PURE__ */ jsx("span", { children: t("ft") }),
1053
1426
  /* @__PURE__ */ jsx("input", { type: "number", placeholder: "4", defaultValue: formRef.current.heightInches || "", onInput: (e) => updateField("heightInches", e.target.value) }),
1054
- /* @__PURE__ */ jsx("span", { children: "in" })
1427
+ /* @__PURE__ */ jsx("span", { children: t("in") })
1055
1428
  ] }) : /* @__PURE__ */ jsx("input", { type: "number", placeholder: "e.g. 175", defaultValue: formRef.current.height || "", onInput: (e) => updateField("height", e.target.value) }),
1056
- /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: "cm", value: "cm" }, { label: "ft", value: "ft" }], value: heightUnit, onChange: setHeightUnit })
1429
+ /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: t("cm"), value: "cm" }, { label: t("ft"), value: "ft" }], value: heightUnit, onChange: setHeightUnit })
1057
1430
  ] }),
1058
1431
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
1059
- /* @__PURE__ */ jsx("label", { children: "Weight *" }),
1432
+ /* @__PURE__ */ jsxs("label", { children: [
1433
+ t("Weight"),
1434
+ " *"
1435
+ ] }),
1060
1436
  /* @__PURE__ */ jsx("input", { type: "number", placeholder: weightUnit === "lbs" ? "e.g. 170" : "e.g. 75", defaultValue: formRef.current.weight || "", onInput: (e) => updateField("weight", e.target.value) }),
1061
- /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: "kg", value: "kg" }, { label: "lbs", value: "lbs" }], value: weightUnit, onChange: setWeightUnit })
1437
+ /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: t("kg"), value: "kg" }, { label: t("lbs"), value: "lbs" }], value: weightUnit, onChange: setWeightUnit })
1062
1438
  ] })
1063
1439
  ] }),
1064
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-disclaimer", children: "Fill in what you know — more measurements = better accuracy." }),
1440
+ /* @__PURE__ */ jsx("p", { className: "ps-tryon-disclaimer", children: t("Fill in what you know — more measurements = better accuracy.") }),
1065
1441
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-form-save-toggle", children: [
1066
1442
  /* @__PURE__ */ jsxs("label", { className: "ps-tryon-form-save-check", children: [
1067
1443
  /* @__PURE__ */ jsx("input", { type: "checkbox", checked: saveToggle, onChange: (e) => setSaveToggle(e.target.checked) }),
1068
- /* @__PURE__ */ jsx("span", { children: "Save as profile" })
1444
+ /* @__PURE__ */ jsx("span", { children: t("Save as profile") })
1069
1445
  ] }),
1070
1446
  saveToggle && /* @__PURE__ */ jsx(
1071
1447
  "input",
1072
1448
  {
1073
1449
  type: "text",
1074
1450
  className: "ps-tryon-form-save-name",
1075
- placeholder: "Profile name (e.g. John, Sarah)",
1451
+ placeholder: t("Profile name (e.g. John, Sarah)"),
1076
1452
  value: saveFormName,
1077
1453
  onChange: (e) => setSaveFormName(e.target.value)
1078
1454
  }
@@ -1082,78 +1458,55 @@ function PrimeStyleTryonInner({
1082
1458
  if (saveToggle && saveFormName.trim()) {
1083
1459
  saveProfile(saveFormName.trim());
1084
1460
  }
1085
- handleSubmit();
1461
+ setSizingLoading(true);
1462
+ submitSizing();
1463
+ setView("size-result");
1086
1464
  }, children: [
1087
- "Get My Size & Try On ",
1465
+ t("Get My Size"),
1466
+ " ",
1088
1467
  /* @__PURE__ */ jsx(ArrowRightIcon, {})
1089
1468
  ] })
1090
1469
  ] }, `form-${formGender}-${sizingUnit}-${heightUnit}-${sizingCountry}-${formKey}`);
1091
1470
  }
1092
- function ProcessingView() {
1093
- const barCb = useCallback((el) => {
1094
- progressBarRef.current = el;
1095
- if (el) el.style.width = `${Math.round(progressRef.current)}%`;
1096
- }, []);
1097
- const pctCb = useCallback((el) => {
1098
- progressTextRef.current = el;
1099
- if (el) el.textContent = `${Math.round(progressRef.current)}%`;
1100
- }, []);
1101
- const statusCb = useCallback((el) => {
1102
- progressStatusRef.current = el;
1103
- }, []);
1104
- return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing", children: [
1105
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing-image-wrap", children: [
1106
- previewUrl && /* @__PURE__ */ jsxs(Fragment, { children: [
1107
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-processing-blur", style: { backgroundImage: `url(${previewUrl})` } }),
1108
- /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo", className: "ps-tryon-processing-model" })
1109
- ] }),
1110
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-line" }),
1111
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-overlay" })
1112
- ] }),
1113
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-section", children: [
1114
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsx("div", { ref: barCb, className: "ps-tryon-progress-bar-fill" }) }),
1115
- /* @__PURE__ */ jsx("span", { ref: pctCb, className: "ps-tryon-progress-pct", children: "0%" })
1116
- ] }),
1117
- /* @__PURE__ */ jsx("div", { ref: statusCb, className: cx("ps-tryon-processing-text", cn.processingText), children: "Preparing your image..." }),
1118
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-processing-sub", cn.processingSubText), children: "This usually takes 15-25 seconds" })
1119
- ] });
1120
- }
1121
- function ResultView() {
1122
- const hasSizing = !!sizingResult || sizingLoading;
1123
- const hasBoth = !!resultImageUrl && hasSizing;
1124
- const [profileName, setProfileName] = useState("");
1471
+ function SizeResultView() {
1125
1472
  const [showFitDetails, setShowFitDetails] = useState(false);
1126
- const confidenceLabel = sizingResult?.confidence === "high" ? "High Confidence" : sizingResult?.confidence === "medium" ? "Medium Confidence" : sizingResult?.confidence === "low" ? "Low Confidence" : "";
1127
- return /* @__PURE__ */ jsxs("div", { className: `ps-tryon-result-layout${hasBoth ? " ps-tryon-result-split" : ""}`, children: [
1128
- resultImageUrl && /* @__PURE__ */ jsx("div", { className: "ps-tryon-result-image-col", children: /* @__PURE__ */ jsx("img", { src: resultImageUrl, alt: "Try-on result", className: cn.resultImage }) }),
1129
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-result-info-col", children: [
1130
- sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend ps-tryon-sizing-loading", children: [
1131
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
1132
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-size-reasoning", children: "Analyzing your size..." })
1133
- ] }),
1134
- sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend", children: [
1135
- /* @__PURE__ */ jsx("h3", { className: "ps-tryon-size-title", children: "Recommended Size" }),
1473
+ const confidenceLabel = sizingResult?.confidence === "high" ? t("High Confidence") : sizingResult?.confidence === "medium" ? t("Medium Confidence") : sizingResult?.confidence === "low" ? t("Low Confidence") : "";
1474
+ return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-result-view", children: [
1475
+ sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend ps-tryon-sizing-loading", children: [
1476
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
1477
+ /* @__PURE__ */ jsx("p", { className: "ps-tryon-size-reasoning", children: t("Analyzing your size...") })
1478
+ ] }),
1479
+ sizingResult && /* @__PURE__ */ jsxs(Fragment, { children: [
1480
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend", children: [
1481
+ /* @__PURE__ */ jsx("h3", { className: "ps-tryon-size-title", children: t("Your Size") }),
1136
1482
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-hero-row", children: [
1137
1483
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-badge", children: sizingResult.recommendedSize }),
1138
1484
  /* @__PURE__ */ jsx("span", { className: `ps-tryon-size-conf-label ps-conf-${sizingResult.confidence}`, children: confidenceLabel })
1139
1485
  ] }),
1486
+ sizingResult.sections && Object.keys(sizingResult.sections).length > 1 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-multi-section", children: [
1487
+ /* @__PURE__ */ jsx("h4", { className: "ps-tryon-fit-summary-title", children: t("Sizing by Garment") }),
1488
+ Object.entries(sizingResult.sections).map(([name, sec]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-section-row", children: [
1489
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-section-name", children: name }),
1490
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-size-badge ps-tryon-section-badge", children: sec.recommendedSize })
1491
+ ] }, name))
1492
+ ] }),
1140
1493
  sizingResult.matchDetails && sizingResult.matchDetails.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-fit-summary", children: [
1141
- /* @__PURE__ */ jsx("h4", { className: "ps-tryon-fit-summary-title", children: "Fit Summary" }),
1494
+ /* @__PURE__ */ jsx("h4", { className: "ps-tryon-fit-summary-title", children: t("Fit Summary") }),
1142
1495
  sizingResult.matchDetails.map((m, i) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-fit-row", children: [
1143
1496
  /* @__PURE__ */ jsx("span", { className: `ps-tryon-fit-icon ps-fit-icon-${m.fit}`, children: m.fit === "good" ? "✓" : m.fit === "tight" ? "↑" : "↓" }),
1144
1497
  /* @__PURE__ */ jsxs("span", { className: "ps-tryon-fit-text", children: [
1145
1498
  /* @__PURE__ */ jsx("strong", { children: m.measurement }),
1146
1499
  " ",
1147
- m.fit === "good" ? "within range" : m.fit === "tight" ? "may be snug" : "may be loose"
1500
+ m.fit === "good" ? t("within range") : m.fit === "tight" ? t("may be snug") : t("may be loose")
1148
1501
  ] })
1149
1502
  ] }, i)),
1150
- /* @__PURE__ */ jsx("button", { className: "ps-tryon-fit-details-toggle", onClick: () => setShowFitDetails(!showFitDetails), children: showFitDetails ? "Hide detailed fit analysis ↑" : "See detailed fit analysis ↓" }),
1503
+ /* @__PURE__ */ jsx("button", { className: "ps-tryon-fit-details-toggle", onClick: () => setShowFitDetails(!showFitDetails), children: showFitDetails ? `${t("Hide details")} ↑` : `${t("See details")} ↓` }),
1151
1504
  showFitDetails && /* @__PURE__ */ jsxs("table", { className: "ps-tryon-fit-table", children: [
1152
1505
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1153
- /* @__PURE__ */ jsx("th", { children: "Area" }),
1154
- /* @__PURE__ */ jsx("th", { children: "You" }),
1155
- /* @__PURE__ */ jsx("th", { children: "Chart" }),
1156
- /* @__PURE__ */ jsx("th", { children: "Fit" })
1506
+ /* @__PURE__ */ jsx("th", { children: t("Area") }),
1507
+ /* @__PURE__ */ jsx("th", { children: t("You") }),
1508
+ /* @__PURE__ */ jsx("th", { children: t("Chart") }),
1509
+ /* @__PURE__ */ jsx("th", { children: t("Fit") })
1157
1510
  ] }) }),
1158
1511
  /* @__PURE__ */ jsx("tbody", { children: sizingResult.matchDetails.map((m, i) => /* @__PURE__ */ jsxs("tr", { children: [
1159
1512
  /* @__PURE__ */ jsx("td", { children: m.measurement }),
@@ -1164,7 +1517,7 @@ function PrimeStyleTryonInner({
1164
1517
  ] })
1165
1518
  ] }),
1166
1519
  sizingResult.internationalSizes && Object.keys(sizingResult.internationalSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-equiv-section", children: [
1167
- /* @__PURE__ */ jsx("h4", { className: "ps-tryon-equiv-title", children: "Equivalent Sizes" }),
1520
+ /* @__PURE__ */ jsx("h4", { className: "ps-tryon-equiv-title", children: t("Equivalent Sizes") }),
1168
1521
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-equiv-chips", children: Object.entries(sizingResult.internationalSizes).map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-equiv-chip", children: [
1169
1522
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-equiv-region", children: k }),
1170
1523
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-equiv-value", children: v })
@@ -1172,35 +1525,57 @@ function PrimeStyleTryonInner({
1172
1525
  ] }),
1173
1526
  (!sizingResult.matchDetails || sizingResult.matchDetails.length === 0) && sizingResult.reasoning && /* @__PURE__ */ jsx("p", { className: "ps-tryon-size-reasoning", children: sizingResult.reasoning })
1174
1527
  ] }),
1175
- /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-result-actions", cn.resultActions), children: [
1176
- /* @__PURE__ */ jsx("button", { onClick: handleDownload, className: cx("ps-tryon-btn-download", cn.downloadButton), children: "Download" }),
1177
- /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-btn-retry", cn.retryButton), children: "Try Another" })
1178
- ] }),
1179
- sizingMethod && !profileSaved && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-save-prompt", children: [
1180
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-save-label", children: "Save your measurements for next time" }),
1181
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-save-row", children: [
1182
- /* @__PURE__ */ jsx("input", { type: "text", placeholder: "Name this profile (e.g. John, Sarah)", value: profileName, onChange: (e) => setProfileName(e.target.value) }),
1183
- activeProfileId ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-save-btn-group", children: [
1184
- /* @__PURE__ */ jsxs("button", { onClick: () => {
1185
- if (profileName.trim()) saveProfile(profileName.trim());
1186
- }, children: [
1187
- "💾",
1188
- " Update"
1189
- ] }),
1190
- /* @__PURE__ */ jsx("button", { className: "ps-tryon-save-new-btn", onClick: () => {
1191
- if (profileName.trim()) saveProfile(profileName.trim(), true);
1192
- }, children: "+ New" })
1193
- ] }) : /* @__PURE__ */ jsxs("button", { onClick: () => {
1194
- if (profileName.trim()) saveProfile(profileName.trim());
1195
- }, children: [
1196
- "💾",
1197
- " Save"
1198
- ] })
1199
- ] })
1528
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-tryon-cta", children: [
1529
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("upload"), children: [
1530
+ t("See how it looks on you"),
1531
+ " ",
1532
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
1533
+ ] }),
1534
+ /* @__PURE__ */ jsx("button", { className: "ps-tryon-btn-secondary", onClick: handleClose, children: t("Done") })
1535
+ ] })
1536
+ ] })
1537
+ ] });
1538
+ }
1539
+ function ProcessingView() {
1540
+ const barCb = useCallback((el) => {
1541
+ progressBarRef.current = el;
1542
+ if (el) el.style.width = `${Math.round(progressRef.current)}%`;
1543
+ }, []);
1544
+ const pctCb = useCallback((el) => {
1545
+ progressTextRef.current = el;
1546
+ if (el) el.textContent = `${Math.round(progressRef.current)}%`;
1547
+ }, []);
1548
+ const statusCb = useCallback((el) => {
1549
+ progressStatusRef.current = el;
1550
+ }, []);
1551
+ return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing", children: [
1552
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing-image-wrap", children: [
1553
+ previewUrl && /* @__PURE__ */ jsxs(Fragment, { children: [
1554
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-processing-blur", style: { backgroundImage: `url(${previewUrl})` } }),
1555
+ /* @__PURE__ */ jsx("img", { src: previewUrl, alt: t("Your photo"), className: "ps-tryon-processing-model" })
1200
1556
  ] }),
1201
- profileSaved && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-save-done", children: [
1202
- /* @__PURE__ */ jsx(CheckIcon, {}),
1203
- " Measurements saved to profile"
1557
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-line" }),
1558
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-overlay" })
1559
+ ] }),
1560
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-section", children: [
1561
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsx("div", { ref: barCb, className: "ps-tryon-progress-bar-fill" }) }),
1562
+ /* @__PURE__ */ jsx("span", { ref: pctCb, className: "ps-tryon-progress-pct", children: "0%" })
1563
+ ] }),
1564
+ /* @__PURE__ */ jsx("div", { ref: statusCb, className: cx("ps-tryon-processing-text", cn.processingText), children: t("Preparing your image...") }),
1565
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-processing-sub", cn.processingSubText), children: t("This usually takes 15-25 seconds") })
1566
+ ] });
1567
+ }
1568
+ function ResultView() {
1569
+ return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-result-layout", children: [
1570
+ resultImageUrl && /* @__PURE__ */ jsx("div", { className: "ps-tryon-result-image-col", children: /* @__PURE__ */ jsx("img", { src: resultImageUrl, alt: t("Try-on result"), className: cn.resultImage }) }),
1571
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-result-info-col", children: [
1572
+ sizingResult && /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-recommend ps-tryon-size-compact", children: /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-hero-row", children: [
1573
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-size-compact-label", children: t("Your size:") }),
1574
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-badge", children: sizingResult.recommendedSize })
1575
+ ] }) }),
1576
+ /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-result-actions", cn.resultActions), children: [
1577
+ /* @__PURE__ */ jsx("button", { onClick: handleDownload, className: cx("ps-tryon-btn-download", cn.downloadButton), children: t("Download") }),
1578
+ /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-btn-retry", cn.retryButton), children: t("Start Over") })
1204
1579
  ] })
1205
1580
  ] })
1206
1581
  ] });
@@ -1208,8 +1583,8 @@ function PrimeStyleTryonInner({
1208
1583
  function ErrorView() {
1209
1584
  return /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-error", cn.error), children: [
1210
1585
  /* @__PURE__ */ jsx(AlertIcon, {}),
1211
- /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-error-text", cn.errorText), children: errorMessage || "Something went wrong" }),
1212
- /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-submit", cn.submitButton), children: "Try Again" })
1586
+ /* @__PURE__ */ jsx("p", { className: cx("ps-tryon-error-text", cn.errorText), children: errorMessage || t("Something went wrong") }),
1587
+ /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-submit", cn.submitButton), children: t("Try Again") })
1213
1588
  ] });
1214
1589
  }
1215
1590
  function DrawerPanel() {
@@ -1217,9 +1592,9 @@ function PrimeStyleTryonInner({
1217
1592
  return /* @__PURE__ */ jsxs("div", { className: `ps-tryon-drawer${drawer ? " ps-tryon-drawer-open" : ""}`, children: [
1218
1593
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-drawer-header", children: [
1219
1594
  /* @__PURE__ */ jsx("button", { className: "ps-tryon-drawer-back", onClick: () => setDrawer(null), children: /* @__PURE__ */ jsx(ArrowLeftIcon, {}) }),
1220
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-drawer-title", children: drawer === "profiles" ? "My Profiles" : "History" })
1595
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-drawer-title", children: drawer === "profiles" ? t("My Profiles") : t("History") })
1221
1596
  ] }),
1222
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-list", children: drawer === "profiles" ? profiles.length === 0 ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-empty", children: "No saved profiles yet." }) : profiles.map((p) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-profile-item", onClick: () => {
1597
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-list", children: drawer === "profiles" ? profiles.length === 0 ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-empty", children: t("No saved profiles yet.") }) : profiles.map((p) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-profile-item", onClick: () => {
1223
1598
  setProfileDetail(p);
1224
1599
  setDrawer(null);
1225
1600
  }, children: [
@@ -1227,18 +1602,18 @@ function PrimeStyleTryonInner({
1227
1602
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-profile-info", children: [
1228
1603
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-profile-name", children: p.name }),
1229
1604
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-profile-detail", children: [
1230
- p.gender === "female" ? "Women's" : "Men's",
1231
- p.heightCm ? ` · ${Math.round(p.heightCm)}cm` : ""
1605
+ p.gender === "female" ? t("Women's") : t("Men's"),
1606
+ p.heightCm ? ` · ${Math.round(p.heightCm)}${t("cm")}` : ""
1232
1607
  ] })
1233
1608
  ] }),
1234
1609
  /* @__PURE__ */ jsx(ChevronRightIcon, {})
1235
- ] }, p.id)) : history.length === 0 ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-empty", children: "No history yet." }) : history.map((entry, idx) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-history-item", children: [
1610
+ ] }, p.id)) : history.length === 0 ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-drawer-empty", children: t("No history yet.") }) : history.map((entry, idx) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-history-item", children: [
1236
1611
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-history-images", children: [
1237
1612
  entry.productImage && /* @__PURE__ */ jsx("img", { src: entry.productImage, alt: "", className: "ps-tryon-history-thumb" }),
1238
1613
  entry.resultImageUrl && /* @__PURE__ */ jsx("img", { src: entry.resultImageUrl, alt: "", className: "ps-tryon-history-result-img" })
1239
1614
  ] }),
1240
1615
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-history-info", children: [
1241
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-history-product", children: entry.productTitle || "Product" }),
1616
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-history-product", children: entry.productTitle || t("Product") }),
1242
1617
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-history-meta", children: [
1243
1618
  entry.profileName ? `${entry.profileName} · ` : "",
1244
1619
  new Date(entry.date).toLocaleDateString()
@@ -1259,20 +1634,20 @@ function PrimeStyleTryonInner({
1259
1634
  if (!profileDetail) return null;
1260
1635
  const p = profileDetail;
1261
1636
  const measurements = [
1262
- { label: "Height", value: p.heightCm, unit: "cm" },
1263
- { label: "Weight", value: p.weightKg, unit: "kg" },
1264
- { label: "Chest", value: p.chest, unit: "cm" },
1265
- { label: "Bust", value: p.bust, unit: "cm" },
1266
- { label: "Waist", value: p.waist, unit: "cm" },
1267
- { label: "Hips", value: p.hips, unit: "cm" },
1268
- { label: "Shoulders", value: p.shoulderWidth, unit: "cm" },
1269
- { label: "Sleeve", value: p.sleeveLength, unit: "cm" },
1270
- { label: "Inseam", value: p.inseam, unit: "cm" },
1271
- { label: "Neck", value: p.neckCircumference, unit: "cm" },
1272
- { label: "Foot", value: p.footLengthCm, unit: "cm" },
1273
- { label: "Shoe EU", value: p.shoeEU ? Number(p.shoeEU) : void 0, unit: "" },
1274
- { label: "Shoe US", value: p.shoeUS ? Number(p.shoeUS) : void 0, unit: "" },
1275
- { label: "Shoe UK", value: p.shoeUK ? Number(p.shoeUK) : void 0, unit: "" }
1637
+ { label: t("Height"), value: p.heightCm, unit: t("cm") },
1638
+ { label: t("Weight"), value: p.weightKg, unit: t("kg") },
1639
+ { label: t("Chest"), value: p.chest, unit: t("cm") },
1640
+ { label: t("Bust"), value: p.bust, unit: t("cm") },
1641
+ { label: t("Waist"), value: p.waist, unit: t("cm") },
1642
+ { label: t("Hips"), value: p.hips, unit: t("cm") },
1643
+ { label: t("Shoulders"), value: p.shoulderWidth, unit: t("cm") },
1644
+ { label: t("Sleeve"), value: p.sleeveLength, unit: t("cm") },
1645
+ { label: t("Inseam"), value: p.inseam, unit: t("cm") },
1646
+ { label: t("Neck"), value: p.neckCircumference, unit: t("cm") },
1647
+ { label: t("Foot"), value: p.footLengthCm, unit: t("cm") },
1648
+ { label: t("Shoe EU"), value: p.shoeEU ? Number(p.shoeEU) : void 0, unit: "" },
1649
+ { label: t("Shoe US"), value: p.shoeUS ? Number(p.shoeUS) : void 0, unit: "" },
1650
+ { label: t("Shoe UK"), value: p.shoeUK ? Number(p.shoeUK) : void 0, unit: "" }
1276
1651
  ].filter((m) => m.value);
1277
1652
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-detail-overlay", onClick: (e) => {
1278
1653
  if (e.target === e.currentTarget) setProfileDetail(null);
@@ -1285,8 +1660,7 @@ function PrimeStyleTryonInner({
1285
1660
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-detail-gender", children: [
1286
1661
  /* @__PURE__ */ jsx(UserIcon, { size: 18 }),
1287
1662
  " ",
1288
- p.gender === "female" ? "Women's" : "Men's",
1289
- " Profile"
1663
+ p.gender === "female" ? t("Women's Profile") : t("Men's Profile")
1290
1664
  ] }),
1291
1665
  measurements.length > 0 && /* @__PURE__ */ jsx("div", { className: "ps-tryon-detail-grid", children: measurements.map((m) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-detail-cell", children: [
1292
1666
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-detail-cell-label", children: m.label }),
@@ -1296,7 +1670,8 @@ function PrimeStyleTryonInner({
1296
1670
  ] })
1297
1671
  ] }, m.label)) }),
1298
1672
  p.createdAt && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-detail-date", children: [
1299
- "Saved ",
1673
+ t("Saved"),
1674
+ " ",
1300
1675
  new Date(p.createdAt).toLocaleDateString()
1301
1676
  ] }),
1302
1677
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-detail-delete", onClick: () => {
@@ -1305,7 +1680,8 @@ function PrimeStyleTryonInner({
1305
1680
  setProfileDetail(null);
1306
1681
  }, children: [
1307
1682
  /* @__PURE__ */ jsx(TrashIcon, {}),
1308
- " Delete Profile"
1683
+ " ",
1684
+ t("Delete Profile")
1309
1685
  ] })
1310
1686
  ] })
1311
1687
  ] }) });
@@ -1314,12 +1690,14 @@ function PrimeStyleTryonInner({
1314
1690
  switch (view) {
1315
1691
  case "welcome":
1316
1692
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(WelcomeView, {}) }, "v-welcome");
1317
- case "upload":
1318
- return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(UploadView, {}) }, "v-upload");
1319
1693
  case "sizing-choice":
1320
1694
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(SizingChoiceView, {}) }, "v-choice");
1321
1695
  case "sizing-form":
1322
1696
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(SizingFormView, {}) }, "v-form");
1697
+ case "size-result":
1698
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(SizeResultView, {}) }, "v-sizeresult");
1699
+ case "upload":
1700
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(UploadView, {}) }, "v-upload");
1323
1701
  case "processing":
1324
1702
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(ProcessingView, {}) }, "v-proc");
1325
1703
  case "result":
@@ -1333,16 +1711,16 @@ function PrimeStyleTryonInner({
1333
1711
  return /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-root", cn.root || className), style: { ...cssVars, ...style }, "data-ps-tryon": true, children: [
1334
1712
  /* @__PURE__ */ jsxs("button", { onClick: handleOpen, className: cx("ps-tryon-btn", cn.button), children: [
1335
1713
  showIcon !== false && (buttonIcon || /* @__PURE__ */ jsx(CameraIcon, {})),
1336
- /* @__PURE__ */ jsx("span", { children: buttonText })
1714
+ /* @__PURE__ */ jsx("span", { children: resolvedButtonText })
1337
1715
  ] }),
1338
1716
  view !== "idle" && /* @__PURE__ */ jsx("div", { className: cx("ps-tryon-overlay", cn.overlay), onClick: (e) => {
1339
1717
  if (e.target === e.currentTarget) handleClose();
1340
1718
  }, children: /* @__PURE__ */ jsxs("div", { className: cx(`ps-tryon-modal${view === "result" && resultImageUrl && sizingResult ? " ps-tryon-modal-wide" : ""}`, cn.modal), onClick: (e) => e.stopPropagation(), children: [
1341
1719
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header", cn.header), children: [
1342
- /* @__PURE__ */ jsx("span", { className: cx("ps-tryon-title", cn.title), children: "Virtual Try-On" }),
1720
+ /* @__PURE__ */ jsx("span", { className: cx("ps-tryon-title", cn.title), children: t("Virtual Try-On") }),
1343
1721
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-header-actions", children: [
1344
- profiles.length > 0 && /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: "Profiles", onClick: () => setDrawer(drawer === "profiles" ? null : "profiles"), children: /* @__PURE__ */ jsx(UserIcon, {}) }),
1345
- history.length > 0 && /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: "History", onClick: () => setDrawer(drawer === "history" ? null : "history"), children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
1722
+ profiles.length > 0 && /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("Profiles"), onClick: () => setDrawer(drawer === "profiles" ? null : "profiles"), children: /* @__PURE__ */ jsx(UserIcon, {}) }),
1723
+ history.length > 0 && /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("History"), onClick: () => setDrawer(drawer === "history" ? null : "history"), children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
1346
1724
  /* @__PURE__ */ jsx("button", { onClick: handleClose, className: cx("ps-tryon-close", cn.closeButton), children: /* @__PURE__ */ jsx(XIcon, {}) })
1347
1725
  ] })
1348
1726
  ] }),
@@ -1352,7 +1730,7 @@ function PrimeStyleTryonInner({
1352
1730
  /* @__PURE__ */ jsx(DrawerPanel, {})
1353
1731
  ] }),
1354
1732
  showPoweredBy && /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-powered", cn.poweredBy), children: [
1355
- "Powered by",
1733
+ t("Powered by"),
1356
1734
  " ",
1357
1735
  /* @__PURE__ */ jsx("a", { href: "https://myaifitting.com", target: "_blank", rel: "noopener noreferrer", children: "PrimeStyle AI" })
1358
1736
  ] })
@@ -1753,8 +2131,27 @@ const STYLES = `
1753
2131
  .ps-tryon-equiv-region { padding: clamp(4px, 0.36vw, 7px) clamp(6px, 0.52vw, 10px); font-size: clamp(9px, 0.63vw, 12px); color: #999; font-weight: 600; background: rgba(255,255,255,0.03); }
1754
2132
  .ps-tryon-equiv-value { padding: clamp(4px, 0.36vw, 7px) clamp(7px, 0.63vw, 12px); font-size: clamp(10px, 0.73vw, 14px); color: #fff; font-weight: 700; }
1755
2133
 
2134
+ /* Multi-section garment sizing (tuxedo/set) */
2135
+ .ps-tryon-multi-section { margin-bottom: clamp(10px, 0.83vw, 16px); }
2136
+ .ps-tryon-section-row { display: flex; align-items: center; justify-content: space-between; padding: clamp(6px, 0.52vw, 10px) 0; border-bottom: 1px solid #222; }
2137
+ .ps-tryon-section-row:last-child { border-bottom: none; }
2138
+ .ps-tryon-section-name { font-size: clamp(11px, 0.78vw, 15px); color: #ccc; font-weight: 500; }
2139
+ .ps-tryon-section-badge { font-size: clamp(12px, 0.83vw, 16px); min-width: auto; padding: clamp(3px, 0.26vw, 5px) clamp(10px, 0.83vw, 16px); }
2140
+
1756
2141
  .ps-tryon-size-reasoning { font-size: clamp(10px, 0.73vw, 14px); color: #ccc; line-height: 1.6; margin-bottom: clamp(8px, 0.73vw, 14px); }
1757
2142
 
2143
+ /* Size Result View (standalone sizing result before try-on) */
2144
+ .ps-tryon-size-result-view { display: flex; flex-direction: column; gap: clamp(12px, 1vw, 20px); }
2145
+ .ps-tryon-tryon-cta { display: flex; flex-direction: column; gap: clamp(8px, 0.7vw, 12px); margin-top: clamp(8px, 0.7vw, 14px); }
2146
+ .ps-tryon-btn-secondary {
2147
+ background: transparent; border: 1.5px solid #444; color: #999; font-size: clamp(11px, 0.83vw, 15px);
2148
+ font-weight: 600; padding: clamp(8px, 0.7vw, 12px) clamp(16px, 1.3vw, 24px); border-radius: clamp(6px, 0.52vw, 10px);
2149
+ cursor: pointer; transition: all 0.2s;
2150
+ }
2151
+ .ps-tryon-btn-secondary:hover { border-color: #666; color: #ccc; }
2152
+ .ps-tryon-size-compact { padding: clamp(6px, 0.5vw, 10px) 0; }
2153
+ .ps-tryon-size-compact-label { font-size: clamp(11px, 0.78vw, 14px); color: #999; font-weight: 500; }
2154
+
1758
2155
  /* Save profile prompt */
1759
2156
  .ps-tryon-save-prompt { margin-top: clamp(8px, 0.73vw, 14px); padding: clamp(8px, 0.73vw, 14px); border: 1px solid #333; border-radius: clamp(8px, 0.63vw, 12px); background: #1a1b1a; }
1760
2157
  .ps-tryon-save-label { font-size: clamp(9px, 0.63vw, 12px); color: #999; margin-bottom: clamp(6px, 0.52vw, 10px); }