@primestyleai/tryon 5.10.177 → 5.10.179

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.
@@ -9530,6 +9530,25 @@ class ApiClient {
9530
9530
  }
9531
9531
  return res.json();
9532
9532
  }
9533
+ async submitTryOnFeedback(input) {
9534
+ const res = await fetch(`${this.baseUrl}/api/v1/tryon/feedback`, {
9535
+ method: "POST",
9536
+ headers: this.headers,
9537
+ body: JSON.stringify({
9538
+ ...input,
9539
+ sessionId: getOrCreateSessionId(),
9540
+ deviceHint: getDeviceHint()
9541
+ })
9542
+ });
9543
+ if (!res.ok) {
9544
+ const data = await res.json().catch(() => ({}));
9545
+ throw new PrimeStyleError(
9546
+ data.message || "Failed to submit try-on feedback",
9547
+ "API_ERROR"
9548
+ );
9549
+ }
9550
+ return res.json();
9551
+ }
9533
9552
  getStreamUrl() {
9534
9553
  const streamUrl = `${this.baseUrl}/api/v1/tryon/stream`;
9535
9554
  return this.apiKey ? `${streamUrl}?key=${encodeURIComponent(this.apiKey)}` : streamUrl;
@@ -10206,6 +10225,52 @@ function parseNum(s) {
10206
10225
  const n2 = parseFloat(s.replace(/[^\d.]/g, ""));
10207
10226
  return isNaN(n2) ? 0 : n2;
10208
10227
  }
10228
+ function normalizeUnit(unit) {
10229
+ const u2 = (unit || "").toLowerCase();
10230
+ if (u2 === "in" || u2 === "inch" || u2 === "inches") return "in";
10231
+ if (u2 === "cm") return "cm";
10232
+ if (u2 === "mm") return "mm";
10233
+ return null;
10234
+ }
10235
+ function detectUnitFromText(text) {
10236
+ const t2 = String(text || "");
10237
+ if (/\bmm\b/i.test(t2)) return "mm";
10238
+ if (/\bcm\b/i.test(t2)) return "cm";
10239
+ if (/\bin\b|inch|inches|["”]/i.test(t2)) return "in";
10240
+ return null;
10241
+ }
10242
+ function convertValue(value, from, to) {
10243
+ if (from === to) return value;
10244
+ const inMm = from === "mm" ? value : from === "cm" ? value * 10 : value * 25.4;
10245
+ if (to === "mm") return inMm;
10246
+ if (to === "cm") return inMm / 10;
10247
+ return inMm / 25.4;
10248
+ }
10249
+ function formatUnitNumber(value, unit) {
10250
+ const precision = unit === "mm" ? 0 : 1;
10251
+ const rounded = Number(value.toFixed(precision));
10252
+ return Number.isInteger(rounded) ? String(rounded) : String(rounded);
10253
+ }
10254
+ function convertNumberTextToUnit(text, from, to) {
10255
+ if (from === to) return text;
10256
+ const converted = text.replace(/\s*(cm|mm|in|inch|inches)\b/ig, "").replace(/(\d+(?:\.\d+)?)/g, (raw) => formatUnitNumber(convertValue(Number(raw), from, to), to)).trim();
10257
+ return converted ? `${converted} ${to}` : text;
10258
+ }
10259
+ function normalizeMeasurementValueText(measurement, value, targetUnit) {
10260
+ if (isUnitlessShoeSizeMeasurement(measurement)) return formatUserMeasurementValue(measurement, value);
10261
+ const sourceUnit = detectUnitFromText(value);
10262
+ if (sourceUnit) return convertNumberTextToUnit(value, sourceUnit, targetUnit);
10263
+ const trimmed = String(value || "").trim();
10264
+ return /\d/.test(trimmed) ? `${trimmed} ${targetUnit}` : trimmed;
10265
+ }
10266
+ function normalizeRangeText(range, targetUnit, header) {
10267
+ const sourceUnit = detectUnitFromText(range) || detectUnitFromText(header);
10268
+ if (!sourceUnit) return String(range || "").trim();
10269
+ return convertNumberTextToUnit(range, sourceUnit, targetUnit);
10270
+ }
10271
+ function promptHeaderLabel(header) {
10272
+ return String(header || "").replace(/\s*\((?:cm|mm|in|inch|inches)\)\s*/ig, "").trim();
10273
+ }
10209
10274
  function isUnitlessShoeSizeMeasurement(measurement) {
10210
10275
  const normalized = measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, " ").trim();
10211
10276
  if (/foot\s*length|length\s*\(cm\)|cm\s*\/\s*jp|mondo|mondopoint/i.test(normalized)) return false;
@@ -10216,11 +10281,15 @@ function formatUserMeasurementValue(measurement, value) {
10216
10281
  return value.replace(/\s*(cm|mm|in|inch|inches)\b/ig, "").trim();
10217
10282
  }
10218
10283
  function computeFit(userValue, chartRange, unit) {
10219
- const { min: rMin, max: rMax } = parseRange(chartRange);
10284
+ const targetUnit = normalizeUnit(unit) || detectUnitFromText(chartRange) || "in";
10285
+ const chartUnit = detectUnitFromText(chartRange);
10286
+ const parsed = parseRange(chartRange);
10287
+ const rMin = chartUnit && chartUnit !== targetUnit ? convertValue(parsed.min, chartUnit, targetUnit) : parsed.min;
10288
+ const rMax = chartUnit && chartUnit !== targetUnit ? convertValue(parsed.max, chartUnit, targetUnit) : parsed.max;
10220
10289
  if (rMin === 0 && rMax === 0) return "good";
10221
- const perfectTol = unit === "cm" ? 1.27 : unit === "mm" ? 12.7 : 0.5;
10222
- const aBitTol = unit === "cm" ? 2.54 : unit === "mm" ? 25.4 : 1;
10223
- const tooFarTol = unit === "cm" ? 5.08 : unit === "mm" ? 50.8 : 2;
10290
+ const perfectTol = targetUnit === "cm" ? 1.27 : targetUnit === "mm" ? 12.7 : 0.5;
10291
+ const aBitTol = targetUnit === "cm" ? 2.54 : targetUnit === "mm" ? 25.4 : 1;
10292
+ const tooFarTol = targetUnit === "cm" ? 5.08 : targetUnit === "mm" ? 50.8 : 2;
10224
10293
  const inRange = userValue >= rMin && userValue <= rMax;
10225
10294
  const overEdge = inRange ? 0 : userValue > rMax ? userValue - rMax : rMin - userValue;
10226
10295
  if (inRange || overEdge <= perfectTol) return "good";
@@ -10243,14 +10312,17 @@ const SKIP_AREAS_FOR_FIT = /* @__PURE__ */ new Set([
10243
10312
  ]);
10244
10313
  function buildFitInfo(matchDetails, poseLines, unit) {
10245
10314
  return matchDetails.filter((m2) => !SKIP_AREAS_FOR_FIT.has(m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim())).map((m2) => {
10246
- const userNum = parseNum(m2.userValue);
10247
- const fit = computeFit(userNum, m2.chartRange, unit);
10315
+ const targetUnit = normalizeUnit(unit) || detectUnitFromText(m2.userValue) || detectUnitFromText(m2.chartRange) || "in";
10316
+ const userValueText = normalizeMeasurementValueText(m2.measurement, m2.userValue, targetUnit);
10317
+ const chartRangeText = normalizeRangeText(m2.chartRange, targetUnit);
10318
+ const userNum = parseNum(userValueText);
10319
+ const fit = computeFit(userNum, chartRangeText, targetUnit);
10248
10320
  const info = {
10249
10321
  area: m2.measurement,
10250
10322
  section: m2.section || void 0,
10251
10323
  fit,
10252
10324
  userValue: userNum || void 0,
10253
- garmentRange: m2.chartRange || void 0
10325
+ garmentRange: chartRangeText || void 0
10254
10326
  };
10255
10327
  if (poseLines) {
10256
10328
  const poseKey = AREA_TO_POSE_KEY[m2.measurement.toLowerCase()];
@@ -10267,6 +10339,7 @@ function buildFitInfo(matchDetails, poseLines, unit) {
10267
10339
  function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, userHeight, userWeight) {
10268
10340
  if (!sizingResult && !sizeGuide && !userHeight && !userWeight) return void 0;
10269
10341
  const out = {};
10342
+ const promptUnit = normalizeUnit(sizingResult?.unit) || detectUnitFromText(sizingResult?.matchDetails?.[0]?.userValue) || detectUnitFromText(Object.values(sizingResult?.sections || {})[0]?.matchDetails?.[0]?.userValue) || "in";
10270
10343
  const baseSize = (selectedSizeOverride || sizingResult?.recommendedSize || "").toString().trim();
10271
10344
  if (userHeight) out.userHeight = userHeight;
10272
10345
  if (userWeight) out.userWeight = userWeight;
@@ -10292,7 +10365,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
10292
10365
  chartRowFit = vStr;
10293
10366
  continue;
10294
10367
  }
10295
- if (vStr) bits.push(`${h} ${vStr}`);
10368
+ if (vStr) bits.push(`${promptHeaderLabel(h) || h} ${normalizeRangeText(vStr, promptUnit, h)}`);
10296
10369
  if (chartRowLength == null && /^length\b|inseam/i.test(h) && vStr) {
10297
10370
  chartRowLength = vStr;
10298
10371
  }
@@ -10341,7 +10414,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
10341
10414
  const h = (secChart.headers[i] || "").trim();
10342
10415
  const baseHeader = h.replace(/\s*\(.*?\)\s*/g, "").trim();
10343
10416
  if (vStr && !/^(size|standard|country|fit|silhouette|category|body[\s_]?type|eu|uk|us|it|jp|cn|kr|ru|br|au)$/i.test(baseHeader)) {
10344
- bits.push(`${h} ${vStr}`);
10417
+ bits.push(`${promptHeaderLabel(h) || h} ${normalizeRangeText(vStr, promptUnit, h)}`);
10345
10418
  }
10346
10419
  }
10347
10420
  if (bits.length) measurementParts.push(`${cleanSec} ${secSize}: ${bits.join(", ")}`);
@@ -10351,29 +10424,33 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
10351
10424
  if (labelParts.length) out.recommendedSize = labelParts.join(", ");
10352
10425
  if (measurementParts.length) out.recommendedSizeMeasurements = measurementParts.join(" | ");
10353
10426
  }
10354
- const seen = /* @__PURE__ */ new Set();
10427
+ const seenUserMeasurements = /* @__PURE__ */ new Set();
10428
+ const seenSelectedMeasurements = /* @__PURE__ */ new Set();
10355
10429
  const userLines = [];
10356
- const push = (md2) => {
10430
+ const selectedMeasurementLines = [];
10431
+ const push = (md2, sectionName) => {
10357
10432
  if (!md2) return;
10358
10433
  for (const m2 of md2) {
10359
- const k2 = m2.measurement.toLowerCase();
10360
- if (seen.has(k2)) continue;
10361
- seen.add(k2);
10362
- if (m2.userValue) userLines.push(`${m2.measurement} ${formatUserMeasurementValue(m2.measurement, m2.userValue)}`);
10434
+ const normalizedMeasurement = m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
10435
+ if (SKIP_AREAS_FOR_FIT.has(normalizedMeasurement)) continue;
10436
+ const selectedKey = sectionName ? `${sectionName.toLowerCase()}:${normalizedMeasurement}` : normalizedMeasurement;
10437
+ if (m2.userValue && !seenUserMeasurements.has(normalizedMeasurement)) {
10438
+ seenUserMeasurements.add(normalizedMeasurement);
10439
+ userLines.push(`${m2.measurement} ${normalizeMeasurementValueText(m2.measurement, m2.userValue, promptUnit)}`);
10440
+ }
10441
+ if (m2.chartRange && !seenSelectedMeasurements.has(selectedKey)) {
10442
+ seenSelectedMeasurements.add(selectedKey);
10443
+ const prefix = sectionName ? `${sectionName} ${m2.measurement}` : m2.measurement;
10444
+ selectedMeasurementLines.push(`${prefix} ${normalizeRangeText(m2.chartRange, promptUnit)}`);
10445
+ }
10363
10446
  }
10364
10447
  };
10365
10448
  push(sizingResult?.matchDetails);
10366
10449
  if (sizingResult?.sections) {
10367
- for (const sec of Object.values(sizingResult.sections)) push(sec.matchDetails);
10450
+ for (const [secName, sec] of Object.entries(sizingResult.sections)) push(sec.matchDetails, secName);
10368
10451
  }
10369
10452
  if (userLines.length) out.userMeasurementsText = userLines.join(", ");
10370
- if (sizeGuide?.headers?.length && sizeGuide.rows?.length) {
10371
- const hdrs = sizeGuide.headers;
10372
- const rowStrings = sizeGuide.rows.slice(0, 20).map(
10373
- (row) => hdrs.map((h, i) => `${h} ${row[i] ?? "—"}`).join(", ")
10374
- );
10375
- out.sizeChartSummary = rowStrings.join(" | ");
10376
- }
10453
+ if (selectedMeasurementLines.length) out.recommendedSizeMeasurements = selectedMeasurementLines.join(", ");
10377
10454
  return Object.keys(out).length ? out : void 0;
10378
10455
  }
10379
10456
  const FALLBACK_FIELDS_FEMALE = [
@@ -10533,6 +10610,24 @@ function logSizeShown(input) {
10533
10610
  fromCache: input.fromCache
10534
10611
  });
10535
10612
  }
10613
+ function logTryOnFeedback(input) {
10614
+ void post("/events/tryon-feedback", {
10615
+ sessionId: getOrCreateSessionId(),
10616
+ deviceHint: getDeviceHint(),
10617
+ jobId: input.jobId,
10618
+ historyEntryId: input.historyEntryId,
10619
+ rating: input.rating,
10620
+ note: input.note,
10621
+ productId: input.productId,
10622
+ productTitle: input.productTitle,
10623
+ productUrl: input.productUrl,
10624
+ recommendedSize: input.recommendedSize,
10625
+ profileLoggedIn: input.profileLoggedIn,
10626
+ profileId: input.profileId,
10627
+ profileName: input.profileName,
10628
+ profileAccessToken: input.profileAccessToken
10629
+ });
10630
+ }
10536
10631
  const ATTR_KEY = "ps_session";
10537
10632
  const PROXY_BASE = "/apps/primestyle";
10538
10633
  const CART_ADD_ENDPOINTS = ["/cart/add.js", "/cart/add"];
@@ -11590,7 +11685,7 @@ function productFitTypeToMeasurementType(fitType) {
11590
11685
  }
11591
11686
  return "body";
11592
11687
  }
11593
- const STYLES$1 = `
11688
+ const STYLES = `
11594
11689
  /* Variable defaults must live on BOTH the root (for the trigger button)
11595
11690
  and the overlay (which is React-portaled to <body> and therefore not
11596
11691
  a descendant of .ps-tryon-root, so the cascade is broken). Without
@@ -11657,6 +11752,7 @@ const STYLES$1 = `
11657
11752
  position: fixed; inset: 0; background: var(--ps-modal-overlay, rgba(0,0,0,0.6));
11658
11753
  display: flex; align-items: center; justify-content: center;
11659
11754
  z-index: 2147483647;
11755
+ pointer-events: auto;
11660
11756
  isolation: isolate;
11661
11757
  contain: layout style;
11662
11758
  padding: 0.83vw;
@@ -12084,9 +12180,22 @@ const STYLES$1 = `
12084
12180
 
12085
12181
  /* ═══════════ V2 Redesign — Editorial luxury ═══════════ */
12086
12182
  .ps-tryon-v2 {
12087
- display: flex; gap: 1.2vw; flex: 1; min-height: 0;
12183
+ display: flex; align-items: stretch; gap: 1.2vw; flex: 1 1 auto; min-height: 0;
12088
12184
  height: 100%; overflow: hidden;
12089
12185
  }
12186
+ .ps-tryon-v2-media-stack {
12187
+ flex: 0 0 43%;
12188
+ min-width: 0;
12189
+ min-height: 0;
12190
+ display: flex;
12191
+ flex-direction: column;
12192
+ gap: 0.45vw;
12193
+ }
12194
+ .ps-tryon-v2-media-stack .ps-tryon-v2-bg {
12195
+ flex: 1 1 auto;
12196
+ width: 100%;
12197
+ min-height: 0;
12198
+ }
12090
12199
 
12091
12200
  /* Left image column — proper contained display.
12092
12201
  No background — the product/try-on image sits directly on the modal
@@ -12112,12 +12221,52 @@ const STYLES$1 = `
12112
12221
 
12113
12222
  /* Right form panel */
12114
12223
  .ps-tryon-v2-panel {
12115
- flex: 1; min-width: 0;
12224
+ flex: 1 1 0; min-width: 0; min-height: 0;
12116
12225
  display: flex; flex-direction: column;
12117
12226
  padding: 0.2vw 0;
12118
12227
  justify-content: center;
12119
12228
  animation: ps-v2-fade 0.18s ease-out forwards;
12120
12229
  }
12230
+ .ps-tryon-v2-result-panel {
12231
+ align-self: stretch;
12232
+ height: 100%;
12233
+ justify-content: flex-start;
12234
+ gap: 0.55vw;
12235
+ padding-bottom: clamp(8px, 0.72vw, 14px);
12236
+ }
12237
+ .ps-tryon-v2-result-panel .ps-tryon-v2-sep {
12238
+ margin-bottom: 0;
12239
+ }
12240
+ .ps-tryon-v2-result-panel .ps-tryon-sr-cards-v2 {
12241
+ flex: 0 0 auto;
12242
+ min-height: 0;
12243
+ }
12244
+ .ps-tryon-v2-result-panel .ps-tryon-photo-strip {
12245
+ flex: 0 0 auto;
12246
+ min-height: 0;
12247
+ margin-top: clamp(10px, 0.75vw, 14px);
12248
+ margin-bottom: clamp(8px, 0.7vw, 12px);
12249
+ }
12250
+ .ps-tryon-v2-result-panel .ps-tryon-sr-card-v2 {
12251
+ min-height: clamp(140px, 10.5vw, 165px);
12252
+ }
12253
+ .ps-tryon-v2-result-panel .ps-tryon-sr-card-v2.ps-full {
12254
+ min-height: clamp(140px, 10.5vw, 165px);
12255
+ }
12256
+ .ps-tryon-v2-result-panel .ps-tryon-photo-strip-cell {
12257
+ aspect-ratio: 1 / 1;
12258
+ height: auto;
12259
+ }
12260
+ .ps-tryon-v2-result-actions {
12261
+ display: flex;
12262
+ align-items: center;
12263
+ justify-content: space-between;
12264
+ margin-top: auto;
12265
+ padding-top: clamp(8px, 0.65vw, 12px);
12266
+ padding-bottom: 0;
12267
+ gap: 0.5vw;
12268
+ flex-shrink: 0;
12269
+ }
12121
12270
  @keyframes ps-v2-fade {
12122
12271
  0% { opacity: 0; }
12123
12272
  100% { opacity: 1; }
@@ -12601,9 +12750,12 @@ const STYLES$1 = `
12601
12750
  .ps-tryon-photo-strip-row {
12602
12751
  display: grid;
12603
12752
  grid-template-columns: repeat(3, 1fr);
12604
- gap: 0.55vw;
12753
+ gap: 0.45vw;
12605
12754
  animation: ps-tryon-photo-strip-fade 0.5s ease;
12606
12755
  }
12756
+ .ps-tryon-photo-strip-row.ps-count-1 .ps-tryon-photo-strip-cell {
12757
+ grid-column: 2;
12758
+ }
12607
12759
  .ps-tryon-photo-strip-cell {
12608
12760
  position: relative;
12609
12761
  display: block;
@@ -12626,7 +12778,7 @@ const STYLES$1 = `
12626
12778
  object-position: center center;
12627
12779
  padding: 0;
12628
12780
  box-sizing: border-box;
12629
- transform: scale(0.94);
12781
+ transform: none;
12630
12782
  transform-origin: center center;
12631
12783
  user-select: none;
12632
12784
  pointer-events: none;
@@ -12667,7 +12819,7 @@ const STYLES$1 = `
12667
12819
  }
12668
12820
  .ps-tryon-photo-strip-cell > img {
12669
12821
  object-position: center center;
12670
- transform: scale(0.94);
12822
+ transform: none;
12671
12823
  }
12672
12824
  }
12673
12825
 
@@ -14253,10 +14405,20 @@ const STYLES$1 = `
14253
14405
  stroke: var(--ps-accent);
14254
14406
  transform: translateY(-1px);
14255
14407
  }
14408
+ .ps-tryon-feedback-star:disabled {
14409
+ cursor: default;
14410
+ }
14411
+ .ps-tryon-feedback-form {
14412
+ display: grid;
14413
+ grid-template-columns: minmax(0, 1fr) auto;
14414
+ gap: 6px;
14415
+ align-items: end;
14416
+ }
14256
14417
  .ps-tryon-feedback-note {
14257
14418
  width: 100%;
14258
14419
  min-width: 0;
14259
- height: clamp(26px, 1.55vw, 32px);
14420
+ min-height: clamp(30px, 1.75vw, 36px);
14421
+ max-height: 78px;
14260
14422
  border: 1px solid #e6eaf2;
14261
14423
  border-radius: clamp(6px, 0.36vw, 8px);
14262
14424
  background: rgba(248, 250, 252, 0.88);
@@ -14264,9 +14426,12 @@ const STYLES$1 = `
14264
14426
  font-family: inherit;
14265
14427
  font-size: clamp(10px, 0.58vw, 12px);
14266
14428
  font-weight: 600;
14267
- padding: 0 clamp(8px, 0.5vw, 10px);
14429
+ line-height: 1.35;
14430
+ padding: clamp(7px, 0.42vw, 9px) clamp(8px, 0.5vw, 10px);
14268
14431
  outline: none;
14269
14432
  box-sizing: border-box;
14433
+ resize: none;
14434
+ overflow-y: auto;
14270
14435
  }
14271
14436
  .ps-tryon-feedback-note::placeholder {
14272
14437
  color: #94a3b8;
@@ -14276,6 +14441,67 @@ const STYLES$1 = `
14276
14441
  border-color: rgba(33,84,239,0.45);
14277
14442
  box-shadow: 0 0 0 3px rgba(33,84,239,0.1);
14278
14443
  }
14444
+ .ps-tryon-feedback-note:disabled {
14445
+ color: #64748b;
14446
+ background: rgba(248, 250, 252, 0.62);
14447
+ cursor: default;
14448
+ }
14449
+ .ps-tryon-feedback-submit {
14450
+ min-height: clamp(30px, 1.75vw, 36px);
14451
+ padding: 0 clamp(9px, 0.55vw, 12px);
14452
+ border: 0;
14453
+ border-radius: clamp(6px, 0.36vw, 8px);
14454
+ background: var(--ps-accent);
14455
+ color: #fff;
14456
+ font-family: inherit;
14457
+ font-size: clamp(10px, 0.56vw, 12px);
14458
+ font-weight: 800;
14459
+ cursor: pointer;
14460
+ white-space: nowrap;
14461
+ }
14462
+ .ps-tryon-feedback-submit:disabled {
14463
+ opacity: 0.48;
14464
+ cursor: default;
14465
+ }
14466
+ .ps-tryon-feedback-status {
14467
+ color: #dc2626;
14468
+ font-size: clamp(10px, 0.56vw, 12px);
14469
+ font-weight: 700;
14470
+ line-height: 1.2;
14471
+ }
14472
+ .ps-result-image-action-bar {
14473
+ width: 100%;
14474
+ display: flex;
14475
+ align-items: center;
14476
+ justify-content: flex-start;
14477
+ gap: clamp(6px, 0.38vw, 9px);
14478
+ flex-wrap: wrap;
14479
+ }
14480
+ .ps-result-image-action {
14481
+ display: inline-flex;
14482
+ align-items: center;
14483
+ justify-content: center;
14484
+ gap: clamp(5px, 0.32vw, 7px);
14485
+ min-height: clamp(30px, 1.75vw, 36px);
14486
+ padding: 0 clamp(10px, 0.65vw, 14px);
14487
+ border-radius: clamp(7px, 0.42vw, 9px);
14488
+ border: 1px solid rgba(226, 232, 240, 0.92);
14489
+ background: #fff;
14490
+ color: var(--ps-text-primary);
14491
+ box-shadow: 0 8px 18px rgba(15, 23, 42, 0.08);
14492
+ font-family: inherit;
14493
+ font-size: clamp(10px, 0.58vw, 12px);
14494
+ font-weight: 800;
14495
+ cursor: pointer;
14496
+ white-space: nowrap;
14497
+ }
14498
+ .ps-result-image-action:hover {
14499
+ border-color: rgba(33,84,239,0.34);
14500
+ color: var(--ps-accent);
14501
+ }
14502
+ .ps-result-image-action svg {
14503
+ flex: 0 0 auto;
14504
+ }
14279
14505
  .ps-tryon-sr-glass-btn {
14280
14506
  background: rgba(255,255,255,0.9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
14281
14507
  border: 1px solid var(--ps-border-color); border-radius: 0.45vw;
@@ -14571,6 +14797,16 @@ const STYLES$1 = `
14571
14797
  box-sizing: border-box;
14572
14798
  }
14573
14799
  .ps-tryon-drawer-open { transform: translateX(0); }
14800
+ .ps-tryon-history-drawer {
14801
+ inset: 0;
14802
+ height: 100%;
14803
+ min-height: 0;
14804
+ padding: 1.04vw 1.25vw;
14805
+ border-radius: 0;
14806
+ transform: translateY(100%);
14807
+ box-shadow: none;
14808
+ }
14809
+ .ps-tryon-history-drawer.ps-tryon-drawer-open { transform: translateY(0); }
14574
14810
  .ps-tryon-drawer-header { display: flex; align-items: center; gap: 0.52vw; padding-bottom: 0.73vw; margin-bottom: 0.73vw; border-bottom: 1px solid var(--ps-border-color); }
14575
14811
  .ps-tryon-drawer-back {
14576
14812
  width: 1.67vw; height: 1.67vw; display: flex; align-items: center; justify-content: center;
@@ -14586,6 +14822,15 @@ const STYLES$1 = `
14586
14822
  font-family: inherit; transition: all 0.2s; flex-shrink: 0; line-height: 1;
14587
14823
  }
14588
14824
  .ps-tryon-drawer-add-btn:hover { border-color: var(--ps-accent); background: rgba(33,84,239,0.1); }
14825
+ .ps-tryon-drawer-close {
14826
+ width: 1.67vw; height: 1.67vw; display: flex; align-items: center; justify-content: center;
14827
+ border: 1.5px solid var(--ps-border-color); border-radius: 0.52vw; background: transparent;
14828
+ cursor: pointer; color: var(--ps-text-secondary); transition: all 0.2s; flex-shrink: 0;
14829
+ }
14830
+ .ps-tryon-drawer-close svg {
14831
+ width: 0.85vw; height: 0.85vw; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round;
14832
+ }
14833
+ .ps-tryon-drawer-close:hover { border-color: var(--ps-accent); color: var(--ps-accent); }
14589
14834
  .ps-tryon-drawer-list { display: flex; flex-direction: column; gap: 0.52vw; max-width: 100%; overflow-x: hidden; }
14590
14835
  .ps-tryon-drawer-empty { text-align: center; padding: 1.67vw 0.83vw; color: var(--ps-text-muted); font-size: 0.73vw; }
14591
14836
 
@@ -14653,6 +14898,101 @@ const STYLES$1 = `
14653
14898
  background: rgba(33,84,239,0.12); border: 1px solid rgba(33,84,239,0.25);
14654
14899
  border-radius: 0.25vw; padding: 0.1vw 0.35vw; margin-top: 0.25vw;
14655
14900
  }
14901
+ .ps-tryon-history-gallery {
14902
+ display: grid;
14903
+ grid-template-columns: repeat(5, minmax(0, 1fr));
14904
+ gap: 0.72vw;
14905
+ }
14906
+ .ps-tryon-history-card {
14907
+ position: relative;
14908
+ min-width: 0;
14909
+ }
14910
+ .ps-tryon-history-card-main {
14911
+ width: 100%;
14912
+ min-width: 0;
14913
+ display: flex;
14914
+ flex-direction: column;
14915
+ gap: 0.34vw;
14916
+ padding: 0;
14917
+ border: 0;
14918
+ background: transparent;
14919
+ color: inherit;
14920
+ font-family: inherit;
14921
+ text-align: left;
14922
+ cursor: pointer;
14923
+ }
14924
+ .ps-tryon-history-card-media {
14925
+ position: relative;
14926
+ width: 100%;
14927
+ aspect-ratio: 3 / 4;
14928
+ border-radius: 0.72vw;
14929
+ overflow: hidden;
14930
+ background: #f4f5f7;
14931
+ border: 1px solid rgba(226, 232, 240, 0.86);
14932
+ box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
14933
+ }
14934
+ .ps-tryon-history-card-img,
14935
+ .ps-tryon-history-card-placeholder {
14936
+ width: 100%;
14937
+ height: 100%;
14938
+ object-fit: cover;
14939
+ object-position: center top;
14940
+ display: block;
14941
+ }
14942
+ .ps-tryon-history-card-placeholder {
14943
+ background: linear-gradient(135deg, rgba(241,245,249,1), rgba(226,232,240,0.7));
14944
+ }
14945
+ .ps-tryon-history-card-product {
14946
+ position: absolute;
14947
+ right: 0.42vw;
14948
+ bottom: 0.42vw;
14949
+ width: 28%;
14950
+ aspect-ratio: 1 / 1;
14951
+ border-radius: 0.42vw;
14952
+ object-fit: cover;
14953
+ background: #fff;
14954
+ border: 1px solid rgba(226, 232, 240, 0.92);
14955
+ box-shadow: 0 8px 18px rgba(15, 23, 42, 0.14);
14956
+ }
14957
+ .ps-tryon-history-card-title {
14958
+ color: var(--ps-text-primary);
14959
+ font-size: 0.66vw;
14960
+ font-weight: 750;
14961
+ line-height: 1.25;
14962
+ overflow: hidden;
14963
+ text-overflow: ellipsis;
14964
+ white-space: nowrap;
14965
+ }
14966
+ .ps-tryon-history-card-meta,
14967
+ .ps-tryon-history-card-sections {
14968
+ color: var(--ps-text-muted);
14969
+ font-size: 0.54vw;
14970
+ font-weight: 600;
14971
+ line-height: 1.2;
14972
+ overflow: hidden;
14973
+ text-overflow: ellipsis;
14974
+ white-space: nowrap;
14975
+ }
14976
+ .ps-tryon-history-card-size {
14977
+ align-self: flex-start;
14978
+ color: var(--ps-accent);
14979
+ background: rgba(33,84,239,0.1);
14980
+ border: 1px solid rgba(33,84,239,0.2);
14981
+ border-radius: 999px;
14982
+ padding: 0.14vw 0.45vw;
14983
+ font-size: 0.52vw;
14984
+ font-weight: 800;
14985
+ }
14986
+ .ps-tryon-history-delete.ps-card-delete {
14987
+ position: absolute;
14988
+ top: 0.42vw;
14989
+ right: 0.42vw;
14990
+ width: 1.5vw;
14991
+ height: 1.5vw;
14992
+ border-radius: 999px;
14993
+ background: rgba(255,255,255,0.9);
14994
+ box-shadow: 0 8px 18px rgba(15,23,42,0.12);
14995
+ }
14656
14996
 
14657
14997
  /* Quiz view */
14658
14998
  .ps-tryon-quiz-progress { display: flex; gap: 0.4vw; margin-bottom: 1vw; }
@@ -14740,6 +15080,12 @@ const STYLES$1 = `
14740
15080
  ────────────────────────────────────────────────────────────────── */
14741
15081
  @media (max-width: 768px) {
14742
15082
  .ps-tryon-drawer { padding: 16px 14px; }
15083
+ .ps-tryon-history-drawer {
15084
+ height: 100%;
15085
+ min-height: 0;
15086
+ padding: 16px 14px;
15087
+ border-radius: 0;
15088
+ }
14743
15089
  .ps-tryon-drawer-header { gap: 10px; padding-bottom: 12px; margin-bottom: 12px; }
14744
15090
  .ps-tryon-drawer-back {
14745
15091
  width: 36px; height: 36px; border-radius: 8px;
@@ -14749,6 +15095,10 @@ const STYLES$1 = `
14749
15095
  .ps-tryon-drawer-add-btn {
14750
15096
  width: 32px; height: 32px; border-radius: 8px; font-size: 20px;
14751
15097
  }
15098
+ .ps-tryon-drawer-close {
15099
+ width: 36px; height: 36px; border-radius: 8px;
15100
+ }
15101
+ .ps-tryon-drawer-close svg { width: 18px; height: 18px; }
14752
15102
  .ps-tryon-drawer-list { gap: 10px; }
14753
15103
  .ps-tryon-drawer-empty { padding: 32px 16px; font-size: 14px; }
14754
15104
 
@@ -14800,6 +15150,36 @@ const STYLES$1 = `
14800
15150
  width: 32px; height: 32px; border-radius: 6px;
14801
15151
  }
14802
15152
  .ps-tryon-history-delete svg { width: 16px; height: 16px; }
15153
+ .ps-tryon-history-gallery {
15154
+ grid-template-columns: repeat(2, minmax(0, 1fr));
15155
+ gap: 12px;
15156
+ }
15157
+ .ps-tryon-history-card-media {
15158
+ border-radius: 12px;
15159
+ }
15160
+ .ps-tryon-history-card-product {
15161
+ right: 7px;
15162
+ bottom: 7px;
15163
+ border-radius: 8px;
15164
+ }
15165
+ .ps-tryon-history-card-title {
15166
+ font-size: 13px;
15167
+ }
15168
+ .ps-tryon-history-card-meta,
15169
+ .ps-tryon-history-card-sections {
15170
+ font-size: 11px;
15171
+ }
15172
+ .ps-tryon-history-card-size {
15173
+ padding: 3px 8px;
15174
+ font-size: 10px;
15175
+ }
15176
+ .ps-tryon-history-delete.ps-card-delete {
15177
+ top: 7px;
15178
+ right: 7px;
15179
+ width: 30px;
15180
+ height: 30px;
15181
+ border-radius: 999px;
15182
+ }
14803
15183
  }
14804
15184
 
14805
15185
  /* Profile detail modal — portaled to body, sits ABOVE the main modal
@@ -17350,10 +17730,32 @@ const STYLES$1 = `
17350
17730
  .ps-tryon-feedback-title { font-size: 11px; }
17351
17731
  .ps-tryon-feedback-star { width: 18px; height: 18px; }
17352
17732
  .ps-tryon-feedback-note {
17353
- height: 30px;
17733
+ min-height: 34px;
17734
+ max-height: 86px;
17354
17735
  border-radius: 8px;
17355
17736
  font-size: 11px;
17356
17737
  }
17738
+ .ps-tryon-feedback-form {
17739
+ gap: 6px;
17740
+ }
17741
+ .ps-tryon-feedback-submit {
17742
+ min-height: 34px;
17743
+ padding: 0 10px;
17744
+ border-radius: 8px;
17745
+ font-size: 11px;
17746
+ }
17747
+ .ps-result-image-action-bar {
17748
+ max-width: 360px;
17749
+ justify-content: flex-start;
17750
+ gap: 7px;
17751
+ }
17752
+ .ps-result-image-action {
17753
+ min-height: 34px;
17754
+ padding: 0 11px;
17755
+ border-radius: 10px;
17756
+ font-size: 11px;
17757
+ box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
17758
+ }
17357
17759
  }
17358
17760
  .ps-msr-product-img-wrap {
17359
17761
  position: relative; flex-shrink: 0;
@@ -17396,7 +17798,7 @@ const STYLES$1 = `
17396
17798
  .ps-msr-feedback-slot {
17397
17799
  position: absolute;
17398
17800
  left: 10px;
17399
- bottom: 54px;
17801
+ bottom: 10px;
17400
17802
  z-index: 3;
17401
17803
  }
17402
17804
  .ps-msr-media-btn {
@@ -17706,7 +18108,7 @@ const STYLES$1 = `
17706
18108
  flex: 1; min-height: 0;
17707
18109
  overflow-y: auto; -webkit-overflow-scrolling: touch;
17708
18110
  display: flex; flex-direction: column;
17709
- gap: 18px; padding: 8px 16px 32px;
18111
+ gap: 18px; padding: 8px 16px 18px;
17710
18112
  }
17711
18113
  /* Topbar: back arrow + section name in uppercase */
17712
18114
  .ps-msd-topbar {
@@ -19697,6 +20099,55 @@ const STYLES$1 = `
19697
20099
  object-fit: contain; display: block;
19698
20100
  }
19699
20101
 
20102
+ .ps-msd-actions {
20103
+ position: sticky;
20104
+ bottom: -1px;
20105
+ z-index: 5;
20106
+ display: flex;
20107
+ align-items: center;
20108
+ gap: 10px;
20109
+ flex-shrink: 0;
20110
+ margin: auto -16px -18px;
20111
+ padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
20112
+ background: rgba(255,255,255,0.96);
20113
+ border-top: 1px solid var(--ps-border-subtle);
20114
+ backdrop-filter: blur(10px);
20115
+ -webkit-backdrop-filter: blur(10px);
20116
+ }
20117
+ .ps-msd-action-back {
20118
+ flex: 0 0 auto;
20119
+ font-size: 13px !important;
20120
+ padding: 10px 6px !important;
20121
+ }
20122
+ .ps-msd-primary-cta {
20123
+ flex: 1 1 0;
20124
+ min-width: 0;
20125
+ display: flex;
20126
+ align-items: center;
20127
+ justify-content: center;
20128
+ gap: 6px;
20129
+ padding: 12px 16px;
20130
+ border: 0;
20131
+ border-radius: 10px;
20132
+ background: var(--ps-accent);
20133
+ color: #fff;
20134
+ font-family: inherit;
20135
+ font-size: 14px;
20136
+ font-weight: 700;
20137
+ cursor: pointer;
20138
+ white-space: nowrap;
20139
+ }
20140
+ .ps-msd-primary-cta.ps-compact {
20141
+ flex: 0 0 auto;
20142
+ min-width: 88px;
20143
+ padding: 10px 14px;
20144
+ font-size: 13px;
20145
+ }
20146
+ .ps-msd-primary-cta:disabled {
20147
+ opacity: 0.6;
20148
+ cursor: default;
20149
+ }
20150
+
19700
20151
  /* RECOMMENDED SIZE card */
19701
20152
  .ps-msd-card {
19702
20153
  background: var(--ps-bg-primary);
@@ -20990,7 +21441,7 @@ function ProfileEditView({
20990
21441
  ] })
20991
21442
  ] });
20992
21443
  }
20993
- function HistoryResultThumb({ entry }) {
21444
+ function HistoryResultThumb({ entry, className = "ps-tryon-history-result-img" }) {
20994
21445
  const [blobUrl, setBlobUrl] = reactExports.useState(null);
20995
21446
  reactExports.useEffect(() => {
20996
21447
  let alive = true;
@@ -21009,7 +21460,7 @@ function HistoryResultThumb({ entry }) {
21009
21460
  }, [entry.id, entry.hasResult, entry.resultImageUrl]);
21010
21461
  const src = entry.resultImageUrl || blobUrl;
21011
21462
  if (!src) return null;
21012
- return /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src, alt: "", className: "ps-tryon-history-result-img" });
21463
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src, alt: "", className });
21013
21464
  }
21014
21465
  function DrawerPanel({
21015
21466
  drawer,
@@ -21034,14 +21485,15 @@ function DrawerPanel({
21034
21485
  setProfiles((prev) => [newProfile, ...prev]);
21035
21486
  setCreatingProfile(false);
21036
21487
  };
21037
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-drawer${drawer ? " ps-tryon-drawer-open" : ""}`, children: [
21488
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-drawer${drawer ? " ps-tryon-drawer-open" : ""}${drawer === "history" ? " ps-tryon-history-drawer" : ""}`, children: [
21038
21489
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-drawer-header", children: [
21039
21490
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-drawer-back", onClick: () => {
21040
21491
  setCreatingProfile(false);
21041
21492
  setDrawer(null);
21042
21493
  }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeftIcon, {}) }),
21043
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-drawer-title", children: creatingProfile ? t2("New Profile") : drawer === "profiles" ? t2("My Profiles") : t2("History") }),
21044
- drawer === "profiles" && !creatingProfile && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-drawer-add-btn", onClick: () => setCreatingProfile(true), children: "+" })
21494
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-drawer-title", children: creatingProfile ? t2("New Profile") : drawer === "profiles" ? t2("My Profiles") : t2("Your try-on history") }),
21495
+ drawer === "profiles" && !creatingProfile && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-drawer-add-btn", onClick: () => setCreatingProfile(true), children: "+" }),
21496
+ drawer === "history" && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-drawer-close", onClick: () => setDrawer(null), "aria-label": t2("Close"), children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6 6l12 12M18 6L6 18" }) }) })
21045
21497
  ] }),
21046
21498
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-drawer-list", children: drawer === "profiles" && creatingProfile ? /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileEditView, { onSave: handleCreateProfile, onCancel: () => setCreatingProfile(false), t: t2 }) : drawer === "profiles" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
21047
21499
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-drawer-create", onClick: () => setCreatingProfile(true), children: [
@@ -21063,33 +21515,25 @@ function DrawerPanel({
21063
21515
  /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRightIcon, {})
21064
21516
  ] }, p2.id))
21065
21517
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: history.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-drawer-empty", children: t2("No history yet.") }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
21066
- history.map((entry, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-item ps-tryon-history-clickable", onClick: () => restoreHistory(entry), children: [
21067
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-images", children: [
21068
- entry.productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: entry.productImage, alt: "", className: "ps-tryon-history-thumb" }),
21069
- /* @__PURE__ */ jsxRuntimeExports.jsx(HistoryResultThumb, { entry })
21070
- ] }),
21071
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-info", children: [
21072
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-history-product", children: entry.productTitle || t2("Product") }),
21073
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-meta", children: [
21518
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-history-gallery", children: history.map((entry, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-card", children: [
21519
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-tryon-history-card-main", onClick: () => restoreHistory(entry), children: [
21520
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-card-media", children: [
21521
+ entry.resultImageUrl || entry.hasResult ? /* @__PURE__ */ jsxRuntimeExports.jsx(HistoryResultThumb, { entry, className: "ps-tryon-history-card-img" }) : entry.productImage ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: entry.productImage, alt: "", className: "ps-tryon-history-card-img" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-history-card-placeholder" }),
21522
+ entry.productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: entry.productImage, alt: "", className: "ps-tryon-history-card-product" })
21523
+ ] }),
21524
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-card-title", children: entry.productTitle || t2("Product") }),
21525
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-history-card-meta", children: [
21074
21526
  entry.profileName ? `${entry.profileName} · ` : "",
21075
21527
  new Date(entry.date).toLocaleDateString()
21076
21528
  ] }),
21077
- entry.recommendedSize && !isMultiSection(entry) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-history-sizing", children: [
21078
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-size-badge", children: entry.recommendedSize }),
21079
- entry.reasoning && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-sizing-reason", children: entry.reasoning })
21080
- ] }),
21081
- isMultiSection(entry) && entry.sizingResult?.sections && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-history-sections", children: Object.entries(entry.sizingResult.sections).map(([name, sec]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-history-section-chip", children: [
21082
- name,
21083
- ": ",
21084
- sec.recommendedSize
21085
- ] }, name)) }),
21086
- (entry.resultImageUrl || entry.hasResult) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-tryon-badge", children: t2("Try-on") })
21529
+ entry.recommendedSize && !isMultiSection(entry) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-card-size", children: entry.recommendedSize }),
21530
+ isMultiSection(entry) && entry.sizingResult?.sections && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-history-card-sections", children: Object.entries(entry.sizingResult.sections).slice(0, 3).map(([name, sec]) => `${name}: ${sec.recommendedSize}`).join(" / ") })
21087
21531
  ] }),
21088
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-history-delete", onClick: (e) => {
21532
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-history-delete ps-card-delete", onClick: (e) => {
21089
21533
  e.stopPropagation();
21090
21534
  setHistory((prev) => prev.filter((_, i) => i !== idx));
21091
- }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}) })
21092
- ] }, entry.id)),
21535
+ }, "aria-label": t2("Delete"), children: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}) })
21536
+ ] }, entry.id)) }),
21093
21537
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-drawer-clear", onClick: () => setHistory([]), children: t2("Clear All") })
21094
21538
  ] }) }) })
21095
21539
  ] });
@@ -21741,29 +22185,6 @@ function CameraIcon() {
21741
22185
  /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "13", r: "4" })
21742
22186
  ] });
21743
22187
  }
21744
- function FitLinesIcon() {
21745
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
21746
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
21747
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
21748
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "9", r: "2" }),
21749
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "15", r: "2" })
21750
- ] });
21751
- }
21752
- function FullSizeIcon() {
21753
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
21754
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
21755
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 3h3a2 2 0 0 1 2 2v3" }),
21756
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 21H5a2 2 0 0 1-2-2v-3" }),
21757
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
21758
- ] });
21759
- }
21760
- function DownloadIcon() {
21761
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
21762
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
21763
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M7 10l5 5 5-5" }),
21764
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 15V3" })
21765
- ] });
21766
- }
21767
22188
  function MultiSectionMobile({
21768
22189
  productImage,
21769
22190
  productTitle,
@@ -21784,6 +22205,8 @@ function MultiSectionMobile({
21784
22205
  onToggleLines,
21785
22206
  onOpenImage,
21786
22207
  onDownload,
22208
+ imageActionBar,
22209
+ feedbackSlot,
21787
22210
  onImageLoad,
21788
22211
  profileCompletionCta,
21789
22212
  t: t2
@@ -21794,6 +22217,7 @@ function MultiSectionMobile({
21794
22217
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msr-scroll", children: [
21795
22218
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msr-eyebrow", children: t2("Sizing Profile") }),
21796
22219
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msr-product", children: [
22220
+ showingTryOn && imageActionBar,
21797
22221
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-msr-product-img-wrap${showingTryOn ? " ps-tryon" : ""}`, children: [
21798
22222
  /* @__PURE__ */ jsxRuntimeExports.jsx(
21799
22223
  "img",
@@ -21808,29 +22232,7 @@ function MultiSectionMobile({
21808
22232
  ),
21809
22233
  showLines && overlayNode,
21810
22234
  tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
21811
- showingTryOn && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
21812
- "button",
21813
- {
21814
- type: "button",
21815
- className: "ps-msr-fit-toggle",
21816
- onClick: onToggleLines,
21817
- "aria-pressed": !!showLines,
21818
- children: [
21819
- /* @__PURE__ */ jsxRuntimeExports.jsx(FitLinesIcon, {}),
21820
- showLines ? t2("Hide Fit") : t2("Show Fit")
21821
- ]
21822
- }
21823
- ),
21824
- showingTryOn && (onOpenImage || onDownload) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msr-media-actions", children: [
21825
- onOpenImage && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-msr-media-btn", onClick: onOpenImage, children: [
21826
- /* @__PURE__ */ jsxRuntimeExports.jsx(FullSizeIcon, {}),
21827
- t2("Full Size")
21828
- ] }),
21829
- onDownload && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-msr-media-btn", onClick: onDownload, children: [
21830
- /* @__PURE__ */ jsxRuntimeExports.jsx(DownloadIcon, {}),
21831
- t2("Download")
21832
- ] })
21833
- ] })
22235
+ showingTryOn && feedbackSlot
21834
22236
  ] }),
21835
22237
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-msr-product-name", children: productTitle })
21836
22238
  ] }),
@@ -21938,7 +22340,7 @@ function ProductPhotoCarouselCard({
21938
22340
  const slide = entries.slice(start, start + PER_SLIDE);
21939
22341
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-photo-strip", role: "group", "aria-label": t2("Product photos"), children: [
21940
22342
  isCompleteLook && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-head", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-photo-strip-badge", children: t2("Complete the look") }) }),
21941
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-row", style: { gridTemplateColumns: `repeat(${Math.max(1, Math.min(PER_SLIDE, slide.length))}, 1fr)` }, children: slide.map((item, i) => {
22343
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `ps-tryon-photo-strip-row ps-count-${slide.length}`, children: slide.map((item, i) => {
21942
22344
  const content = /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: item.image, alt: item.title || productTitle || "", draggable: false });
21943
22345
  return item.href ? /* @__PURE__ */ jsxRuntimeExports.jsx(
21944
22346
  "a",
@@ -22041,10 +22443,36 @@ function ProfileCompletionCta({
22041
22443
  }
22042
22444
  );
22043
22445
  }
22044
- function TryOnExperienceFeedback({ t: t2, isMobile }) {
22446
+ function TryOnExperienceFeedback({
22447
+ t: t2,
22448
+ isMobile,
22449
+ onSubmit
22450
+ }) {
22045
22451
  const [rating, setRating] = reactExports.useState(0);
22046
22452
  const [note, setNote] = reactExports.useState("");
22047
22453
  const [expanded, setExpanded] = reactExports.useState(false);
22454
+ const [status, setStatus] = reactExports.useState("idle");
22455
+ const noteRef = reactExports.useRef(null);
22456
+ const canEdit = status !== "submitting" && status !== "sent";
22457
+ const canSubmit = (rating > 0 || note.trim().length > 0) && canEdit;
22458
+ const resizeNote = reactExports.useCallback((node) => {
22459
+ if (!node) return;
22460
+ node.style.height = "auto";
22461
+ node.style.height = `${Math.min(node.scrollHeight, isMobile ? 86 : 78)}px`;
22462
+ }, [isMobile]);
22463
+ reactExports.useEffect(() => {
22464
+ resizeNote(noteRef.current);
22465
+ }, [note, resizeNote]);
22466
+ const submitFeedback = reactExports.useCallback(async () => {
22467
+ if (!canSubmit) return;
22468
+ setStatus("submitting");
22469
+ try {
22470
+ await onSubmit?.({ rating: rating || void 0, note: note.trim() || void 0 });
22471
+ setStatus("sent");
22472
+ } catch {
22473
+ setStatus("error");
22474
+ }
22475
+ }, [canSubmit, note, onSubmit, rating]);
22048
22476
  if (!expanded) {
22049
22477
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
22050
22478
  "button",
@@ -22078,7 +22506,12 @@ function TryOnExperienceFeedback({ t: t2, isMobile }) {
22078
22506
  {
22079
22507
  type: "button",
22080
22508
  className: `ps-tryon-feedback-star${value <= rating ? " is-active" : ""}`,
22081
- onClick: () => setRating(value),
22509
+ onClick: () => {
22510
+ if (!canEdit) return;
22511
+ setRating(value);
22512
+ setStatus("idle");
22513
+ },
22514
+ disabled: !canEdit,
22082
22515
  role: "radio",
22083
22516
  "aria-checked": rating === value,
22084
22517
  "aria-label": `${value} ${t2("stars")}`,
@@ -22087,16 +22520,76 @@ function TryOnExperienceFeedback({ t: t2, isMobile }) {
22087
22520
  value
22088
22521
  )) })
22089
22522
  ] }),
22090
- /* @__PURE__ */ jsxRuntimeExports.jsx(
22091
- "input",
22092
- {
22093
- className: "ps-tryon-feedback-note",
22094
- value: note,
22095
- onChange: (event) => setNote(event.target.value),
22096
- placeholder: t2("Optional note"),
22097
- maxLength: 120
22098
- }
22099
- )
22523
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-feedback-form", children: [
22524
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
22525
+ "textarea",
22526
+ {
22527
+ ref: noteRef,
22528
+ className: "ps-tryon-feedback-note",
22529
+ value: note,
22530
+ onChange: (event) => {
22531
+ if (!canEdit) return;
22532
+ setNote(event.target.value);
22533
+ setStatus("idle");
22534
+ resizeNote(event.currentTarget);
22535
+ },
22536
+ disabled: !canEdit,
22537
+ placeholder: t2("Optional note"),
22538
+ maxLength: 1e3,
22539
+ rows: 1
22540
+ }
22541
+ ),
22542
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
22543
+ "button",
22544
+ {
22545
+ type: "button",
22546
+ className: "ps-tryon-feedback-submit",
22547
+ onClick: submitFeedback,
22548
+ disabled: !canSubmit,
22549
+ "aria-label": t2("Send feedback"),
22550
+ children: status === "submitting" ? t2("Sending") : status === "sent" ? t2("Sent") : t2("Send")
22551
+ }
22552
+ )
22553
+ ] }),
22554
+ status === "error" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-feedback-status", children: t2("Couldn't send. Try again.") })
22555
+ ] });
22556
+ }
22557
+ function ResultImageActionBar({
22558
+ showLines,
22559
+ canShowFit,
22560
+ onToggleFit,
22561
+ onOpenImage,
22562
+ onDownload,
22563
+ t: t2
22564
+ }) {
22565
+ if (!canShowFit && !onOpenImage && !onDownload) return null;
22566
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-result-image-action-bar", children: [
22567
+ canShowFit && onToggleFit && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-result-image-action", onClick: onToggleFit, children: [
22568
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
22569
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
22570
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
22571
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "9", r: "2" }),
22572
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "15", r: "2" })
22573
+ ] }),
22574
+ showLines ? t2("Hide Fit") : t2("Show Fit")
22575
+ ] }),
22576
+ onOpenImage && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-result-image-action", onClick: onOpenImage, children: [
22577
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
22578
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
22579
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 3h3a2 2 0 0 1 2 2v3" }),
22580
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 21H5a2 2 0 0 1-2-2v-3" }),
22581
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
22582
+ ] }),
22583
+ t2("Full Size")
22584
+ ] }),
22585
+ onDownload && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-result-image-action", onClick: onDownload, children: [
22586
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
22587
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
22588
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M7 10l5 5 5-5" }),
22589
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 15V3" })
22590
+ ] }),
22591
+ t2("Download")
22592
+ ] })
22100
22593
  ] });
22101
22594
  }
22102
22595
  function garmentIconForSection(name) {
@@ -22623,12 +23116,14 @@ function SectionDetailView({
22623
23116
  onImageLoad,
22624
23117
  onOpenImage,
22625
23118
  onDownload,
23119
+ onFeedbackSubmit,
22626
23120
  onTryOn,
22627
23121
  tryOnProcessing,
22628
23122
  tryOnStartedAt,
22629
23123
  backLabel,
22630
23124
  internationalSizes,
22631
23125
  continueLabel,
23126
+ onContinue,
22632
23127
  renderRaw = false,
22633
23128
  sectionFound,
22634
23129
  allSizes,
@@ -22905,14 +23400,19 @@ function SectionDetailView({
22905
23400
  });
22906
23401
  return isFootwear ? rows.filter((row) => isFootLengthMeasurement(row.area)) : rows;
22907
23402
  }, [sectionResult, lengthEntry, userMeasurements, renderRaw, allSizes, displaySize, selectedLength, isFootwear]);
23403
+ const activeFitKeyRef = reactExports.useRef("");
22908
23404
  reactExports.useEffect(() => {
22909
23405
  if (!onActiveFitChange) return;
22910
- onActiveFitChange(fitRows.map((r2) => ({
23406
+ const nextRows = fitRows.map((r2) => ({
22911
23407
  area: r2.area,
22912
23408
  userNum: r2.userNum ?? 0,
22913
23409
  chartLabel: r2.chartLabel ?? "",
22914
23410
  fit: r2.fit ?? "good"
22915
- })));
23411
+ }));
23412
+ const nextKey = JSON.stringify(nextRows);
23413
+ if (activeFitKeyRef.current === nextKey) return;
23414
+ activeFitKeyRef.current = nextKey;
23415
+ onActiveFitChange(nextRows);
22916
23416
  }, [fitRows, onActiveFitChange]);
22917
23417
  const allowsLengthDisplay = !renderRaw && !isFootwear;
22918
23418
  const secAny = sectionResult;
@@ -23054,62 +23554,38 @@ function SectionDetailView({
23054
23554
  ] }),
23055
23555
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-msd-topbar-spacer" })
23056
23556
  ] }),
23057
- productImage && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-msd-image${isTryOnImage ? " ps-tryon" : ""}`, children: [
23058
- /* @__PURE__ */ jsxRuntimeExports.jsx(
23059
- "img",
23060
- {
23061
- src: productImage,
23062
- alt: productTitle || "",
23063
- className: "ps-msd-image-img",
23064
- onLoad: onImageLoad,
23065
- onClick: isTryOnImage && onOpenImage ? onOpenImage : void 0,
23066
- style: isTryOnImage && onOpenImage ? { cursor: "zoom-in" } : void 0
23067
- }
23068
- ),
23069
- showLines && (renderOverlayWithFit ? renderOverlayWithFit(fitRows.map((r2) => ({
23070
- area: r2.area,
23071
- userNum: r2.userNum ?? 0,
23072
- chartLabel: r2.chartLabel ?? "",
23073
- fit: r2.fit ?? "good"
23074
- }))) : overlayNode),
23075
- tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
23076
- isTryOnImage && !isFootwear && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
23077
- "button",
23557
+ productImage && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
23558
+ isTryOnImage && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(
23559
+ ResultImageActionBar,
23078
23560
  {
23079
- type: "button",
23080
- className: "ps-msr-fit-toggle",
23081
- onClick: onToggleLines,
23082
- "aria-pressed": !!showLines,
23083
- children: [
23084
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
23085
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
23086
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
23087
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "9", r: "2" }),
23088
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "15", r: "2" })
23089
- ] }),
23090
- showLines ? t2("Hide Fit") : t2("Show Fit")
23091
- ]
23561
+ showLines: !!showLines,
23562
+ canShowFit: !isFootwear && !!onToggleLines,
23563
+ onToggleFit: onToggleLines,
23564
+ onOpenImage,
23565
+ onDownload,
23566
+ t: t2
23092
23567
  }
23093
23568
  ),
23094
- isTryOnImage && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msr-feedback-slot", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, isMobile: true }) }),
23095
- isTryOnImage && (onOpenImage || onDownload) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msr-media-actions", children: [
23096
- onOpenImage && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-msr-media-btn", onClick: onOpenImage, children: [
23097
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
23098
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
23099
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 3h3a2 2 0 0 1 2 2v3" }),
23100
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 21H5a2 2 0 0 1-2-2v-3" }),
23101
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
23102
- ] }),
23103
- t2("Full Size")
23104
- ] }),
23105
- onDownload && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-msr-media-btn", onClick: onDownload, children: [
23106
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
23107
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
23108
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M7 10l5 5 5-5" }),
23109
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 15V3" })
23110
- ] }),
23111
- t2("Download")
23112
- ] })
23569
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-msd-image${isTryOnImage ? " ps-tryon" : ""}`, children: [
23570
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
23571
+ "img",
23572
+ {
23573
+ src: productImage,
23574
+ alt: productTitle || "",
23575
+ className: "ps-msd-image-img",
23576
+ onLoad: onImageLoad,
23577
+ onClick: isTryOnImage && onOpenImage ? onOpenImage : void 0,
23578
+ style: isTryOnImage && onOpenImage ? { cursor: "zoom-in" } : void 0
23579
+ }
23580
+ ),
23581
+ showLines && (renderOverlayWithFit ? renderOverlayWithFit(fitRows.map((r2) => ({
23582
+ area: r2.area,
23583
+ userNum: r2.userNum ?? 0,
23584
+ chartLabel: r2.chartLabel ?? "",
23585
+ fit: r2.fit ?? "good"
23586
+ }))) : overlayNode),
23587
+ tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
23588
+ isTryOnImage && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msr-feedback-slot", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, isMobile: true, onSubmit: onFeedbackSubmit }) })
23113
23589
  ] })
23114
23590
  ] }),
23115
23591
  false,
@@ -23274,14 +23750,13 @@ function SectionDetailView({
23274
23750
  t2("based on your measurements and the garment's tailoring chart.")
23275
23751
  ] }) }),
23276
23752
  profileCompletionCta && /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, isMobile: true, t: t2 }),
23277
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: 10, padding: "12px 0 4px", flexShrink: 0, alignItems: "center" }, children: [
23753
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msd-actions", children: [
23278
23754
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
23279
23755
  "button",
23280
23756
  {
23281
23757
  type: "button",
23282
- className: "ps-bp-back-btn",
23758
+ className: "ps-bp-back-btn ps-msd-action-back",
23283
23759
  onClick: onBack,
23284
- style: { fontSize: 13, padding: "10px 6px", flexShrink: 0 },
23285
23760
  children: [
23286
23761
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
23287
23762
  " ",
@@ -23295,25 +23770,7 @@ function SectionDetailView({
23295
23770
  type: "button",
23296
23771
  onClick: onTryOn,
23297
23772
  disabled: tryOnProcessing,
23298
- style: {
23299
- flex: "1 1 0",
23300
- minWidth: 0,
23301
- padding: "12px 16px",
23302
- borderRadius: 10,
23303
- background: "var(--ps-accent)",
23304
- color: "white",
23305
- border: "none",
23306
- fontSize: 14,
23307
- fontWeight: 700,
23308
- fontFamily: "inherit",
23309
- cursor: tryOnProcessing ? "default" : "pointer",
23310
- opacity: tryOnProcessing ? 0.6 : 1,
23311
- display: "flex",
23312
- alignItems: "center",
23313
- justifyContent: "center",
23314
- gap: 6,
23315
- whiteSpace: "nowrap"
23316
- },
23773
+ className: "ps-msd-primary-cta",
23317
23774
  children: [
23318
23775
  /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, { size: 14 }),
23319
23776
  tryOnProcessing ? `${t2("Generating try-on…")}${tryOnElapsedS > 0 ? ` ${tryOnElapsedS}s` : ""}` : t2("Try It On")
@@ -23324,24 +23781,7 @@ function SectionDetailView({
23324
23781
  {
23325
23782
  type: "button",
23326
23783
  onClick: onBack,
23327
- style: {
23328
- flex: isCompactMobileContinue ? "0 0 auto" : "1 1 0",
23329
- minWidth: isCompactMobileContinue ? 88 : 0,
23330
- padding: isCompactMobileContinue ? "10px 14px" : "12px 16px",
23331
- borderRadius: 10,
23332
- background: "var(--ps-accent)",
23333
- color: "white",
23334
- border: "none",
23335
- fontSize: isCompactMobileContinue ? 13 : 14,
23336
- fontWeight: 700,
23337
- fontFamily: "inherit",
23338
- cursor: "pointer",
23339
- display: "flex",
23340
- alignItems: "center",
23341
- justifyContent: "center",
23342
- gap: 6,
23343
- whiteSpace: "nowrap"
23344
- },
23784
+ className: `ps-msd-primary-cta${isCompactMobileContinue ? " ps-compact" : ""}`,
23345
23785
  children: [
23346
23786
  continueLabel || t2("Continue"),
23347
23787
  " →"
@@ -23564,7 +24004,7 @@ function SectionDetailView({
23564
24004
  ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
23565
24005
  "button",
23566
24006
  {
23567
- onClick: onBack,
24007
+ onClick: continueLabel ? onContinue || onBack : onBack,
23568
24008
  style: {
23569
24009
  padding: "0.45vw 1.2vw",
23570
24010
  borderRadius: "0.4vw",
@@ -23600,11 +24040,14 @@ function SizeResultView({
23600
24040
  productImages,
23601
24041
  productCarouselItems,
23602
24042
  productTitle,
24043
+ productUrl,
23603
24044
  productMaterial,
23604
24045
  productDescription,
23605
24046
  sizingUnit,
23606
24047
  setView,
23607
24048
  handleDownload,
24049
+ onContinueShopping,
24050
+ onTryOnFeedbackSubmit,
23608
24051
  selectedFile,
23609
24052
  previewUrl,
23610
24053
  handleFileSelect,
@@ -24123,6 +24566,7 @@ function SizeResultView({
24123
24566
  return lengthEntries.find((le2) => le2.section.headers.some((h) => /height|altezza|estatura|\(cm\)/i.test(h))) || null;
24124
24567
  })(),
24125
24568
  onBack: () => setActiveSection(null),
24569
+ onContinue: onContinueShopping || onClose,
24126
24570
  internationalSizes: entry.secResult?.internationalSizes,
24127
24571
  productImage: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24128
24572
  productTitle,
@@ -24134,6 +24578,7 @@ function SizeResultView({
24134
24578
  onToggleLines: suppressFitOverlayActions ? void 0 : () => setShowLines(!showLines),
24135
24579
  onOpenImage: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0,
24136
24580
  onDownload: resultImageUrl && !tryOnProcessing ? handleDownload : void 0,
24581
+ onFeedbackSubmit: onTryOnFeedbackSubmit,
24137
24582
  onImageLoad: handleImgLoad,
24138
24583
  overlayNode: tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
24139
24584
  /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
@@ -24172,20 +24617,34 @@ function SizeResultView({
24172
24617
  ] });
24173
24618
  }
24174
24619
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
24175
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24176
- /* @__PURE__ */ jsxRuntimeExports.jsx(
24177
- "img",
24620
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-media-stack", children: [
24621
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(
24622
+ ResultImageActionBar,
24178
24623
  {
24179
- src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24180
- alt: productTitle,
24181
- className: "ps-tryon-v2-bg-img",
24182
- onLoad: handleImgLoad,
24183
- style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
24184
- onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
24624
+ showLines: !!showLines,
24625
+ canShowFit: !suppressFitOverlayActions,
24626
+ onToggleFit: () => setShowLines(!showLines),
24627
+ onOpenImage: () => setZoomImageUrl(resultImageUrl),
24628
+ onDownload: handleDownload,
24629
+ t: t2
24185
24630
  }
24186
24631
  ),
24187
- tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
24188
- /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing })
24632
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24633
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
24634
+ "img",
24635
+ {
24636
+ src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24637
+ alt: productTitle,
24638
+ className: "ps-tryon-v2-bg-img",
24639
+ onLoad: handleImgLoad,
24640
+ style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
24641
+ onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
24642
+ }
24643
+ ),
24644
+ tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
24645
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
24646
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, onSubmit: onTryOnFeedbackSubmit }) })
24647
+ ] })
24189
24648
  ] }),
24190
24649
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
24191
24650
  mismatchNotice,
@@ -24207,9 +24666,11 @@ function SizeResultView({
24207
24666
  return lengthEntries.find((le2) => le2.section.headers.some((h) => /height|altezza|estatura|\(cm\)/i.test(h))) || null;
24208
24667
  })(),
24209
24668
  onBack: () => setActiveSection(null),
24669
+ onContinue: onContinueShopping || onClose,
24210
24670
  internationalSizes: entry.secResult?.internationalSizes,
24211
24671
  tryOnProcessing,
24212
24672
  tryOnStartedAt,
24673
+ onFeedbackSubmit: onTryOnFeedbackSubmit,
24213
24674
  t: t2,
24214
24675
  isFootwear: measurementType === "foot",
24215
24676
  userGender: shoeUserGender,
@@ -24248,11 +24709,23 @@ function SizeResultView({
24248
24709
  setGuideFile(selectedFile || null);
24249
24710
  setShowPhotoGuide(true);
24250
24711
  },
24251
- onClose,
24712
+ onClose: onContinueShopping || onClose,
24252
24713
  showLines,
24253
24714
  onToggleLines: suppressFitOverlayActions ? void 0 : () => setShowLines(!showLines),
24254
24715
  onOpenImage: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0,
24255
24716
  onDownload: resultImageUrl && !tryOnProcessing ? handleDownload : void 0,
24717
+ imageActionBar: resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
24718
+ ResultImageActionBar,
24719
+ {
24720
+ showLines: !!showLines,
24721
+ canShowFit: !suppressFitOverlayActions,
24722
+ onToggleFit: () => setShowLines(!showLines),
24723
+ onOpenImage: () => setZoomImageUrl(resultImageUrl),
24724
+ onDownload: handleDownload,
24725
+ t: t2
24726
+ }
24727
+ ) : null,
24728
+ feedbackSlot: resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msr-feedback-slot", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, isMobile: true, onSubmit: onTryOnFeedbackSubmit }) }) : null,
24256
24729
  onImageLoad: handleImgLoad,
24257
24730
  profileCompletionCta: profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, isMobile: true, t: t2 }) : null,
24258
24731
  overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -24285,60 +24758,55 @@ function SizeResultView({
24285
24758
  ) : (
24286
24759
  /* ── Desktop section picker: split layout — image left, image cards right ── */
24287
24760
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
24288
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24289
- /* @__PURE__ */ jsxRuntimeExports.jsx(
24290
- "img",
24761
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-media-stack", children: [
24762
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(
24763
+ ResultImageActionBar,
24291
24764
  {
24292
- src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24293
- alt: productTitle,
24294
- className: "ps-tryon-v2-bg-img",
24295
- onLoad: handleImgLoad,
24296
- style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
24297
- onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
24765
+ showLines: !!showLines,
24766
+ canShowFit: !suppressFitOverlayActions,
24767
+ onToggleFit: () => setShowLines(!showLines),
24768
+ onOpenImage: () => setZoomImageUrl(resultImageUrl),
24769
+ onDownload: handleDownload,
24770
+ t: t2
24298
24771
  }
24299
24772
  ),
24300
- tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
24301
- /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
24302
- resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
24303
- const all = [...sizingResult?.matchDetails || []];
24304
- if (sizingResult?.sections) {
24305
- for (const sec of Object.values(sizingResult.sections)) {
24306
- if (sec.matchDetails) all.push(...sec.matchDetails);
24773
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24774
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
24775
+ "img",
24776
+ {
24777
+ src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24778
+ alt: productTitle,
24779
+ className: "ps-tryon-v2-bg-img",
24780
+ onLoad: handleImgLoad,
24781
+ style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
24782
+ onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
24307
24783
  }
24308
- }
24309
- const seen = /* @__PURE__ */ new Set();
24310
- return all.filter((m2) => {
24311
- const k2 = m2.measurement.toLowerCase();
24312
- if (seen.has(k2)) return false;
24313
- seen.add(k2);
24314
- return true;
24315
- }).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit }));
24316
- })(), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
24317
- resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-img-actions", children: [
24318
- /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2 }),
24319
- !suppressFitOverlayActions && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: [
24320
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { marginRight: "0.3vw" }, children: [
24321
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
24322
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
24323
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "7", cy: "9", r: "2" }),
24324
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "17", cy: "15", r: "2" })
24325
- ] }),
24326
- showLines ? t2("Hide Fit") : t2("Show Fit")
24327
- ] }),
24328
- suppressFitOverlayActions && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setZoomImageUrl(resultImageUrl), children: t2("Full Size") }),
24329
- /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: handleDownload, children: [
24330
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { marginRight: "0.3vw" }, children: [
24331
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
24332
- /* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "7 10 12 15 17 10" }),
24333
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
24334
- ] }),
24335
- t2("Download")
24336
- ] })
24784
+ ),
24785
+ tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
24786
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
24787
+ resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
24788
+ const all = [...sizingResult?.matchDetails || []];
24789
+ if (sizingResult?.sections) {
24790
+ for (const sec of Object.values(sizingResult.sections)) {
24791
+ if (sec.matchDetails) all.push(...sec.matchDetails);
24792
+ }
24793
+ }
24794
+ const seen = /* @__PURE__ */ new Set();
24795
+ return all.filter((m2) => {
24796
+ const k2 = m2.measurement.toLowerCase();
24797
+ if (seen.has(k2)) return false;
24798
+ seen.add(k2);
24799
+ return true;
24800
+ }).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit }));
24801
+ })(), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
24802
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, onSubmit: onTryOnFeedbackSubmit }) })
24337
24803
  ] })
24338
24804
  ] }),
24339
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
24340
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Perfect Fit") }),
24341
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap any section for detailed breakdown") }),
24805
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel ps-tryon-v2-result-panel", children: [
24806
+ 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: [
24807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Perfect Fit") }),
24808
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap any section for detailed breakdown") })
24809
+ ] }),
24342
24810
  mismatchNotice,
24343
24811
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-sep" }),
24344
24812
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-cards-v2", children: sectionEntries.map(({ name, secResult }, idx) => {
@@ -24379,8 +24847,7 @@ function SizeResultView({
24379
24847
  sectionImg && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: sectionImg, alt: name, className: "ps-tryon-sr-card-v2-img" })
24380
24848
  ] }, name);
24381
24849
  }) }),
24382
- profileCompletionCta && /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, t: t2 }),
24383
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: "0.5vw", gap: "0.5vw" }, children: [
24850
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-actions", children: [
24384
24851
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-bp-back-btn", onClick: () => setView("body-profile"), type: "button", children: [
24385
24852
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
24386
24853
  " ",
@@ -24391,7 +24858,7 @@ function SizeResultView({
24391
24858
  {
24392
24859
  className: "ps-tryon-v2-cta",
24393
24860
  style: { marginTop: 0 },
24394
- onClick: onClose,
24861
+ onClick: onContinueShopping || onClose,
24395
24862
  children: [
24396
24863
  t2("Continue Shopping"),
24397
24864
  " →"
@@ -24402,7 +24869,7 @@ function SizeResultView({
24402
24869
  {
24403
24870
  className: "ps-tryon-v2-cta",
24404
24871
  style: { marginTop: 0 },
24405
- onClick: onClose,
24872
+ onClick: onContinueShopping || onClose,
24406
24873
  children: [
24407
24874
  t2("Continue Shopping"),
24408
24875
  " →"
@@ -24472,6 +24939,7 @@ function SizeResultView({
24472
24939
  if (resultImageUrl) onResetTryOn?.();
24473
24940
  setView("body-profile");
24474
24941
  },
24942
+ onContinue: onContinueShopping || onClose,
24475
24943
  backLabel: t2("Back"),
24476
24944
  internationalSizes: singleInternationalSizes,
24477
24945
  onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
@@ -24492,6 +24960,7 @@ function SizeResultView({
24492
24960
  onToggleLines: suppressFitOverlayActions ? void 0 : () => setShowLines(!showLines),
24493
24961
  onOpenImage: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0,
24494
24962
  onDownload: resultImageUrl && !tryOnProcessing ? handleDownload : void 0,
24963
+ onFeedbackSubmit: onTryOnFeedbackSubmit,
24495
24964
  onImageLoad: handleImgLoad,
24496
24965
  overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
24497
24966
  MeasurementOverlay,
@@ -24509,38 +24978,46 @@ function SizeResultView({
24509
24978
  ] });
24510
24979
  }
24511
24980
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
24512
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24513
- /* @__PURE__ */ jsxRuntimeExports.jsx(
24514
- "img",
24515
- {
24516
- src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24517
- alt: productTitle,
24518
- className: "ps-tryon-v2-bg-img",
24519
- onLoad: handleImgLoad,
24520
- style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
24521
- onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
24522
- }
24523
- ),
24524
- tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
24525
- /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
24526
- resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(
24527
- MeasurementOverlay,
24981
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-media-stack", children: [
24982
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(
24983
+ ResultImageActionBar,
24528
24984
  {
24529
- lines: poseLines,
24530
- fitRows: activeFitRows.length > 0 ? activeFitRows : (sizingResult?.matchDetails || []).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit })),
24531
- show: showLines,
24532
- imgWidth: imgDims.w,
24533
- imgHeight: imgDims.h
24985
+ showLines: !!showLines,
24986
+ canShowFit: !suppressFitOverlayActions,
24987
+ onToggleFit: () => setShowLines(!showLines),
24988
+ onOpenImage: () => setZoomImageUrl(resultImageUrl),
24989
+ onDownload: handleDownload,
24990
+ t: t2
24534
24991
  }
24535
24992
  ),
24536
- resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-img-actions", children: [
24537
- /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2 }),
24538
- !suppressFitOverlayActions && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t2("Hide Fit") : t2("Show Fit") }),
24539
- suppressFitOverlayActions && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setZoomImageUrl(resultImageUrl), children: t2("Full Size") }),
24540
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: handleDownload, children: t2("Download") })
24993
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
24994
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
24995
+ "img",
24996
+ {
24997
+ src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
24998
+ alt: productTitle,
24999
+ className: "ps-tryon-v2-bg-img",
25000
+ onLoad: handleImgLoad,
25001
+ style: resultImageUrl && !tryOnProcessing ? { cursor: "zoom-in" } : void 0,
25002
+ onClick: resultImageUrl && !tryOnProcessing ? () => setZoomImageUrl(resultImageUrl) : void 0
25003
+ }
25004
+ ),
25005
+ tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
25006
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
25007
+ resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(
25008
+ MeasurementOverlay,
25009
+ {
25010
+ lines: poseLines,
25011
+ fitRows: activeFitRows.length > 0 ? activeFitRows : (sizingResult?.matchDetails || []).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit })),
25012
+ show: showLines,
25013
+ imgWidth: imgDims.w,
25014
+ imgHeight: imgDims.h
25015
+ }
25016
+ ),
25017
+ resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnExperienceFeedback, { t: t2, onSubmit: onTryOnFeedbackSubmit }) })
24541
25018
  ] })
24542
25019
  ] }),
24543
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
25020
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-v2-panel${activeSection ? "" : " ps-tryon-v2-result-panel"}`, children: [
24544
25021
  mismatchNotice,
24545
25022
  activeSection === sectionName ? (
24546
25023
  /* DETAIL VIEW — full size table, same as multi-garment */
@@ -24563,12 +25040,14 @@ function SizeResultView({
24563
25040
  setActiveSection(null);
24564
25041
  }
24565
25042
  },
25043
+ onContinue: onContinueShopping || onClose,
24566
25044
  backLabel: t2("Back"),
24567
25045
  internationalSizes: singleInternationalSizes,
24568
25046
  onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
24569
25047
  continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
24570
25048
  tryOnProcessing,
24571
25049
  tryOnStartedAt,
25050
+ onFeedbackSubmit: onTryOnFeedbackSubmit,
24572
25051
  t: t2,
24573
25052
  renderRaw: isAccessory,
24574
25053
  isFootwear: measurementType === "foot",
@@ -24616,7 +25095,7 @@ function SizeResultView({
24616
25095
  }
24617
25096
  ) }),
24618
25097
  hasCarousel && /* @__PURE__ */ jsxRuntimeExports.jsx(ProductPhotoCarouselCard, { items: carouselItems.length > 0 ? carouselItems : void 0, photos: productImages, productTitle, t: t2 }),
24619
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: "0.5vw", gap: "0.5vw" }, children: [
25098
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-actions", children: [
24620
25099
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
24621
25100
  "button",
24622
25101
  {
@@ -24633,10 +25112,10 @@ function SizeResultView({
24633
25112
  ]
24634
25113
  }
24635
25114
  ),
24636
- resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
25115
+ resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onContinueShopping || onClose, children: [
24637
25116
  t2("Continue Shopping"),
24638
25117
  " →"
24639
- ] }) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
25118
+ ] }) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onContinueShopping || onClose, children: [
24640
25119
  t2("Continue Shopping"),
24641
25120
  " →"
24642
25121
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -31694,11 +32173,18 @@ if (typeof document !== "undefined") {
31694
32173
  if (!document.getElementById(id2)) {
31695
32174
  const el2 = document.createElement("style");
31696
32175
  el2.id = id2;
31697
- el2.textContent = STYLES$1;
32176
+ el2.textContent = STYLES;
31698
32177
  document.head.appendChild(el2);
31699
32178
  }
31700
32179
  }
31701
32180
  const PROFILE_COMPLETION_DRAFT_KEY = "profile_completion_draft";
32181
+ const TRYON_FEEDBACK_SUBMITTED_KEY = "tryon_feedback_submitted";
32182
+ function buildTryOnFeedbackKey(input) {
32183
+ if (input.jobId) return `job:${input.jobId}`;
32184
+ if (input.historyEntryId) return `history:${input.historyEntryId}`;
32185
+ if (input.resultImageUrl) return `result:${input.resultImageUrl.slice(0, 180)}`;
32186
+ return `fallback:${input.productId || input.productTitle || "product"}:${input.recommendedSize || "size"}`;
32187
+ }
31702
32188
  function positiveNumber(value) {
31703
32189
  const n2 = typeof value === "number" ? value : parseFloat(String(value ?? ""));
31704
32190
  return Number.isFinite(n2) && n2 > 0 ? n2 : void 0;
@@ -31739,6 +32225,27 @@ function sanitizeHistoryEntry(entry) {
31739
32225
  hasResult: entry.hasResult || !!entry.resultImageUrl || void 0
31740
32226
  };
31741
32227
  }
32228
+ function comparableProductId(value) {
32229
+ return String(value || "").trim().replace(/^gid:\/\/shopify\/Product\//i, "").replace(/^Product\//i, "");
32230
+ }
32231
+ function historyEntryMatchesProduct(entry, productId, productTitle) {
32232
+ const currentId = comparableProductId(productId);
32233
+ const entryId = comparableProductId(entry.productId);
32234
+ if (currentId && entryId) return currentId === entryId;
32235
+ const currentTitle = String(productTitle || "").trim().toLowerCase();
32236
+ const entryTitle = String(entry.productTitle || "").trim().toLowerCase();
32237
+ return !!currentTitle && !!entryTitle && currentTitle === entryTitle;
32238
+ }
32239
+ function hasCompletedTryOnResult(entry) {
32240
+ return !!(entry.resultImageUrl || entry.hasResult);
32241
+ }
32242
+ function dispatchTryOnCompleteEvent(detail) {
32243
+ if (typeof window === "undefined") return;
32244
+ try {
32245
+ window.dispatchEvent(new CustomEvent("primestyle:tryon-complete", { detail }));
32246
+ } catch {
32247
+ }
32248
+ }
31742
32249
  function computeMatchScore(recData) {
31743
32250
  if (!recData) return null;
31744
32251
  const all = [];
@@ -31782,6 +32289,7 @@ function PrimeStyleTryonInner({
31782
32289
  productCarouselItems,
31783
32290
  garmentReferenceImage,
31784
32291
  productTitle = "Product",
32292
+ productUrl,
31785
32293
  productId,
31786
32294
  productCategory,
31787
32295
  productGender,
@@ -31793,6 +32301,7 @@ function PrimeStyleTryonInner({
31793
32301
  productDescription,
31794
32302
  productMaterial,
31795
32303
  buttonText,
32304
+ limitOneColorTryOnPerProduct = false,
31796
32305
  apiUrl,
31797
32306
  showPoweredBy = true,
31798
32307
  showIcon = true,
@@ -31834,6 +32343,17 @@ function PrimeStyleTryonInner({
31834
32343
  }, [productTagsKey]);
31835
32344
  const effectiveProductImages = stableProductImages.length > 0 ? stableProductImages : void 0;
31836
32345
  const effectiveProductCarouselItems = stableProductCarouselItems.length > 0 ? stableProductCarouselItems : void 0;
32346
+ const effectiveProductUrl = reactExports.useMemo(() => {
32347
+ const source = productUrl?.trim();
32348
+ if (source) {
32349
+ try {
32350
+ return typeof window !== "undefined" ? new URL(source, window.location.origin).href : source;
32351
+ } catch {
32352
+ return source;
32353
+ }
32354
+ }
32355
+ return typeof window !== "undefined" ? window.location.href : void 0;
32356
+ }, [productUrl]);
31837
32357
  const resolvedProductFitType = reactExports.useMemo(
31838
32358
  () => detectProductFitType({
31839
32359
  productFitType,
@@ -32011,12 +32531,15 @@ function PrimeStyleTryonInner({
32011
32531
  const [profileAuthLoadingProvider, setProfileAuthLoadingProvider] = reactExports.useState(null);
32012
32532
  const [history, setHistory] = reactExports.useState(() => lsGet("history", []).map(normalizeHistoryEntry));
32013
32533
  const currentHistoryEntryIdRef = reactExports.useRef(null);
32534
+ const currentTryOnJobIdRef = reactExports.useRef(null);
32535
+ const submittedFeedbackKeysRef = reactExports.useRef(new Set(lsGet(TRYON_FEEDBACK_SUBMITTED_KEY, [])));
32014
32536
  const [mobileMenuOpen, setMobileMenuOpen] = reactExports.useState(false);
32015
32537
  const mobileMenuBtnRef = reactExports.useRef(null);
32016
32538
  const [restoredProductImage, setRestoredProductImage] = reactExports.useState(null);
32017
32539
  const [restoredProductImages, setRestoredProductImages] = reactExports.useState(null);
32018
32540
  const [restoredProductCarouselItems, setRestoredProductCarouselItems] = reactExports.useState(null);
32019
32541
  const [restoredProductTitle, setRestoredProductTitle] = reactExports.useState(null);
32542
+ const [restoredProductUrl, setRestoredProductUrl] = reactExports.useState(null);
32020
32543
  const [activeProfileId, setActiveProfileIdState] = reactExports.useState(() => getActiveProfileId());
32021
32544
  const [estimatingProfileIds, setEstimatingProfileIds] = reactExports.useState(() => /* @__PURE__ */ new Set());
32022
32545
  const [deleteConfirmId, setDeleteConfirmId] = reactExports.useState(null);
@@ -32534,6 +33057,13 @@ function PrimeStyleTryonInner({
32534
33057
  setSizingResult(null);
32535
33058
  setResultImageUrl(null);
32536
33059
  currentHistoryEntryIdRef.current = null;
33060
+ currentTryOnJobIdRef.current = null;
33061
+ setRestoredProductImage(null);
33062
+ setRestoredProductImages(null);
33063
+ setRestoredProductCarouselItems(null);
33064
+ setRestoredProductTitle(null);
33065
+ setRestoredProductUrl(null);
33066
+ setRestoredProductUrl(null);
32537
33067
  setSizingLoading(true);
32538
33068
  setEstimationDone(hasStored);
32539
33069
  if (hasStored) {
@@ -32621,12 +33151,18 @@ function PrimeStyleTryonInner({
32621
33151
  setProfileSaved(false);
32622
33152
  formRef.current = {};
32623
33153
  setFormGender("male");
33154
+ setRestoredProductImage(null);
33155
+ setRestoredProductImages(null);
33156
+ setRestoredProductCarouselItems(null);
33157
+ setRestoredProductTitle(null);
33158
+ setRestoredProductUrl(null);
32624
33159
  if (!tryOnInFlight) {
32625
33160
  setResultImageUrl(null);
32626
33161
  setSizingResult(null);
32627
33162
  historySavedRef.current = false;
32628
33163
  historyTryonSavedRef.current = false;
32629
33164
  currentHistoryEntryIdRef.current = null;
33165
+ currentTryOnJobIdRef.current = null;
32630
33166
  unsubRef.current?.();
32631
33167
  unsubRef.current = null;
32632
33168
  if (pollingRef.current) {
@@ -32731,6 +33267,7 @@ function PrimeStyleTryonInner({
32731
33267
  return;
32732
33268
  }
32733
33269
  if (update.status === "completed" && update.imageUrl) {
33270
+ currentTryOnJobIdRef.current = update.galleryId;
32734
33271
  if (shouldUseShopifyCartAttribution(apiUrl)) {
32735
33272
  setLastCompletedProduct(effectiveProductId ?? null, productTitle || null);
32736
33273
  }
@@ -32757,6 +33294,14 @@ function PrimeStyleTryonInner({
32757
33294
  cleanupJob();
32758
33295
  setTryOnProcessing(false);
32759
33296
  setTryOnStartedAt(null);
33297
+ dispatchTryOnCompleteEvent({
33298
+ jobId: update.galleryId,
33299
+ historyEntryId: currentHistoryEntryIdRef.current,
33300
+ productId: effectiveProductId,
33301
+ productTitle,
33302
+ recommendedSize: sizingResultRef.current?.recommendedSize,
33303
+ resultImageUrl: update.imageUrl
33304
+ });
32760
33305
  onComplete?.({ jobId: update.galleryId, imageUrl: update.imageUrl });
32761
33306
  }
32762
33307
  } else if (update.status === "failed") {
@@ -33039,10 +33584,12 @@ function PrimeStyleTryonInner({
33039
33584
  setSizingResult(null);
33040
33585
  setResultImageUrl(null);
33041
33586
  currentHistoryEntryIdRef.current = null;
33587
+ currentTryOnJobIdRef.current = null;
33042
33588
  setRestoredProductImage(null);
33043
33589
  setRestoredProductImages(null);
33044
33590
  setRestoredProductCarouselItems(null);
33045
33591
  setRestoredProductTitle(null);
33592
+ setRestoredProductUrl(null);
33046
33593
  if (previewUrl) URL.revokeObjectURL(previewUrl);
33047
33594
  setSelectedFile(null);
33048
33595
  selectedFileRef.current = null;
@@ -33108,6 +33655,7 @@ function PrimeStyleTryonInner({
33108
33655
  historySavedRef.current = false;
33109
33656
  historyTryonSavedRef.current = false;
33110
33657
  currentHistoryEntryIdRef.current = null;
33658
+ currentTryOnJobIdRef.current = null;
33111
33659
  setSizingLoading(true);
33112
33660
  setEstimationDone(false);
33113
33661
  setView("size-result");
@@ -33338,6 +33886,7 @@ function PrimeStyleTryonInner({
33338
33886
  selectedFileRef.current = overrideFile;
33339
33887
  }
33340
33888
  completedRef.current = false;
33889
+ currentTryOnJobIdRef.current = null;
33341
33890
  setTryOnProcessing(true);
33342
33891
  setTryOnStartedAt(Date.now());
33343
33892
  const vtoCategory = measurementTypeToVtoCategory(measurementType, resolvedProductFitType);
@@ -33475,6 +34024,7 @@ function PrimeStyleTryonInner({
33475
34024
  modelImageId: modelImageIdRef.current ?? void 0
33476
34025
  }
33477
34026
  );
34027
+ currentTryOnJobIdRef.current = response.jobId;
33478
34028
  if (response.modelImageId) modelImageIdRef.current = response.modelImageId;
33479
34029
  onProcessing?.(response.jobId);
33480
34030
  const usePollingOnly = shouldUseShopifyCartAttribution(apiUrl);
@@ -33545,6 +34095,59 @@ function PrimeStyleTryonInner({
33545
34095
  }).catch(() => window.open(resultImageUrl, "_blank"));
33546
34096
  }
33547
34097
  }, [resultImageUrl]);
34098
+ const handleContinueShopping = reactExports.useCallback(() => {
34099
+ const historyUrl = restoredProductUrl || "";
34100
+ if (historyUrl && typeof window !== "undefined") {
34101
+ try {
34102
+ window.open(new URL(historyUrl, window.location.origin).href, "_blank", "noopener,noreferrer");
34103
+ } catch {
34104
+ window.open(historyUrl, "_blank", "noopener,noreferrer");
34105
+ }
34106
+ }
34107
+ handleClose();
34108
+ }, [handleClose, restoredProductUrl]);
34109
+ const handleTryOnFeedbackSubmit = reactExports.useCallback(async ({ rating, note }) => {
34110
+ const profileLoggedIn = Boolean(profileSession);
34111
+ const activeProfile = profileLoggedIn ? profiles.find((profile) => profile.id === activeProfileId) : null;
34112
+ const jobId = currentTryOnJobIdRef.current ?? void 0;
34113
+ const historyEntryId = currentHistoryEntryIdRef.current ?? void 0;
34114
+ const feedbackKey = buildTryOnFeedbackKey({
34115
+ jobId,
34116
+ historyEntryId,
34117
+ resultImageUrl,
34118
+ productId: effectiveProductId,
34119
+ productTitle: restoredProductTitle || productTitle,
34120
+ recommendedSize: sizingResult?.recommendedSize
34121
+ });
34122
+ if (submittedFeedbackKeysRef.current.has(feedbackKey)) return;
34123
+ submittedFeedbackKeysRef.current.add(feedbackKey);
34124
+ lsSet(TRYON_FEEDBACK_SUBMITTED_KEY, Array.from(submittedFeedbackKeysRef.current).slice(-80));
34125
+ const payload = {
34126
+ jobId,
34127
+ historyEntryId,
34128
+ rating,
34129
+ note: note?.trim() || void 0,
34130
+ productId: effectiveProductId,
34131
+ productTitle: restoredProductTitle || productTitle,
34132
+ productUrl: restoredProductUrl || effectiveProductUrl,
34133
+ recommendedSize: sizingResult?.recommendedSize,
34134
+ profileLoggedIn,
34135
+ profileId: activeProfile?.id,
34136
+ profileName: activeProfile?.name,
34137
+ profileAccessToken: profileSession?.accessToken
34138
+ };
34139
+ if (shouldUseShopifyCartAttribution(apiUrl)) {
34140
+ logTryOnFeedback(payload);
34141
+ return;
34142
+ }
34143
+ try {
34144
+ await apiRef.current?.submitTryOnFeedback(payload);
34145
+ } catch (error) {
34146
+ submittedFeedbackKeysRef.current.delete(feedbackKey);
34147
+ lsSet(TRYON_FEEDBACK_SUBMITTED_KEY, Array.from(submittedFeedbackKeysRef.current).slice(-80));
34148
+ throw error;
34149
+ }
34150
+ }, [activeProfileId, apiUrl, effectiveProductId, effectiveProductUrl, productTitle, profileSession, profiles, restoredProductTitle, restoredProductUrl, resultImageUrl, sizingResult?.recommendedSize]);
33548
34151
  const handleRetry = reactExports.useCallback(() => {
33549
34152
  completedRef.current = false;
33550
34153
  cleanupJob();
@@ -33555,6 +34158,12 @@ function PrimeStyleTryonInner({
33555
34158
  historySavedRef.current = false;
33556
34159
  historyTryonSavedRef.current = false;
33557
34160
  currentHistoryEntryIdRef.current = null;
34161
+ currentTryOnJobIdRef.current = null;
34162
+ setRestoredProductImage(null);
34163
+ setRestoredProductImages(null);
34164
+ setRestoredProductCarouselItems(null);
34165
+ setRestoredProductTitle(null);
34166
+ setRestoredProductUrl(null);
33558
34167
  setErrorMessage(null);
33559
34168
  setSizingMethod(null);
33560
34169
  setSizingResult(null);
@@ -33691,6 +34300,8 @@ function PrimeStyleTryonInner({
33691
34300
  id: id2,
33692
34301
  productId,
33693
34302
  productTitle,
34303
+ productUrl: effectiveProductUrl,
34304
+ jobId: currentTryOnJobIdRef.current ?? void 0,
33694
34305
  productImage,
33695
34306
  productImages: effectiveProductImages?.slice(0, 12),
33696
34307
  productCarouselItems: effectiveProductCarouselItems?.slice(0, 12),
@@ -33725,7 +34336,7 @@ function PrimeStyleTryonInner({
33725
34336
  return next;
33726
34337
  });
33727
34338
  return id2;
33728
- }, [productId, productTitle, productImage, effectiveProductImages, effectiveProductCarouselItems, resultImageUrl, sizingResult, sizeGuide, activeProfileId, profiles, selectedFile]);
34339
+ }, [productId, productTitle, effectiveProductUrl, productImage, effectiveProductImages, effectiveProductCarouselItems, resultImageUrl, sizingResult, sizeGuide, activeProfileId, profiles, selectedFile]);
33729
34340
  const persistHistoryResult = reactExports.useCallback((entryId, imageUrl, cleanupWhenIdle) => {
33730
34341
  void (async () => {
33731
34342
  const durableResultUrl = durableHistoryImageUrl(imageUrl);
@@ -33743,6 +34354,7 @@ function PrimeStyleTryonInner({
33743
34354
  if (entry.id !== entryId) return entry;
33744
34355
  return {
33745
34356
  ...entry,
34357
+ ...currentTryOnJobIdRef.current ? { jobId: currentTryOnJobIdRef.current } : {},
33746
34358
  ...durableResultUrl ? { resultImageUrl: durableResultUrl } : {},
33747
34359
  ...storedResult ? { hasResult: true } : {}
33748
34360
  };
@@ -33798,6 +34410,7 @@ function PrimeStyleTryonInner({
33798
34410
  if (idx < 0) return prev;
33799
34411
  const updated = {
33800
34412
  ...prev[idx],
34413
+ ...currentTryOnJobIdRef.current ? { jobId: currentTryOnJobIdRef.current } : {},
33801
34414
  ...durableResultUrl ? { resultImageUrl: durableResultUrl } : {},
33802
34415
  hasResult: true,
33803
34416
  ...selectedSizes.length ? { selectedSizes } : {}
@@ -33815,6 +34428,7 @@ function PrimeStyleTryonInner({
33815
34428
  historySavedRef.current = false;
33816
34429
  historyTryonSavedRef.current = false;
33817
34430
  currentHistoryEntryIdRef.current = null;
34431
+ currentTryOnJobIdRef.current = null;
33818
34432
  }
33819
34433
  }, [view, sizingResult, resultImageUrl]);
33820
34434
  const restoreHistory = reactExports.useCallback((entry) => {
@@ -33825,6 +34439,7 @@ function PrimeStyleTryonInner({
33825
34439
  historySavedRef.current = true;
33826
34440
  historyTryonSavedRef.current = !!entry.resultImageUrl || !!entry.hasResult;
33827
34441
  currentHistoryEntryIdRef.current = entry.id;
34442
+ currentTryOnJobIdRef.current = entry.jobId || null;
33828
34443
  autoTryOnFiredRef.current = true;
33829
34444
  const isCurrentProductEntry = entry.productId && productId ? entry.productId === productId : !!entry.productTitle && entry.productTitle === productTitle;
33830
34445
  setRestoredProductImage(entry.productImage || null);
@@ -33835,6 +34450,7 @@ function PrimeStyleTryonInner({
33835
34450
  entry.productCarouselItems?.length ? entry.productCarouselItems : isCurrentProductEntry && effectiveProductCarouselItems?.length ? effectiveProductCarouselItems : null
33836
34451
  );
33837
34452
  setRestoredProductTitle(entry.productTitle || null);
34453
+ setRestoredProductUrl(entry.productUrl || null);
33838
34454
  if (entry.sizingResult) {
33839
34455
  setSizingResult(entry.sizingResult);
33840
34456
  } else if (entry.recommendedSize) {
@@ -33889,6 +34505,21 @@ function PrimeStyleTryonInner({
33889
34505
  setDrawer(null);
33890
34506
  setView("size-result");
33891
34507
  }, [cleanupJob, productId, productTitle, effectiveProductImages, effectiveProductCarouselItems]);
34508
+ const savedOneColorFitEntry = reactExports.useMemo(() => {
34509
+ if (!limitOneColorTryOnPerProduct) return null;
34510
+ return history.find(
34511
+ (entry) => hasCompletedTryOnResult(entry) && !!entry.recommendedSize && historyEntryMatchesProduct(entry, effectiveProductId, productTitle)
34512
+ ) || null;
34513
+ }, [limitOneColorTryOnPerProduct, history, effectiveProductId, productTitle]);
34514
+ const storefrontButtonText = savedOneColorFitEntry?.recommendedSize ? `${t2("Your size is")} ${savedOneColorFitEntry.recommendedSize}` : resolvedButtonText;
34515
+ const handleStorefrontButtonClick = reactExports.useCallback(() => {
34516
+ if (savedOneColorFitEntry) {
34517
+ onOpen?.();
34518
+ restoreHistory(savedOneColorFitEntry);
34519
+ return;
34520
+ }
34521
+ handleOpen();
34522
+ }, [handleOpen, onOpen, restoreHistory, savedOneColorFitEntry]);
33892
34523
  const updateField = reactExports.useCallback((key, val) => {
33893
34524
  formRef.current[key] = val;
33894
34525
  }, []);
@@ -34072,11 +34703,14 @@ function PrimeStyleTryonInner({
34072
34703
  productImages: restoredProductImages || (restoredProductImage ? [restoredProductImage] : effectiveProductImages),
34073
34704
  productCarouselItems: restoredProductCarouselItems || (restoredProductImage ? void 0 : effectiveProductCarouselItems),
34074
34705
  productTitle: restoredProductTitle || productTitle,
34706
+ productUrl: restoredProductUrl || effectiveProductUrl,
34075
34707
  productMaterial,
34076
34708
  productDescription,
34077
34709
  sizingUnit,
34078
34710
  setView,
34079
34711
  handleDownload,
34712
+ onContinueShopping: handleContinueShopping,
34713
+ onTryOnFeedbackSubmit: handleTryOnFeedbackSubmit,
34080
34714
  selectedFile,
34081
34715
  previewUrl,
34082
34716
  handleFileSelect,
@@ -34355,15 +34989,12 @@ function PrimeStyleTryonInner({
34355
34989
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
34356
34990
  "button",
34357
34991
  {
34358
- onClick: (e) => {
34359
- console.log("[ps-sdk] button click event fired", e);
34360
- handleOpen();
34361
- },
34992
+ onClick: handleStorefrontButtonClick,
34362
34993
  className: cx(cx("ps-tryon-btn", isTextTrigger ? "ps-tryon-btn--text" : void 0), cn.button),
34363
34994
  type: "button",
34364
34995
  children: [
34365
34996
  !isTextTrigger && showIcon !== false && (buttonIcon || /* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, {})),
34366
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: resolvedButtonText })
34997
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: storefrontButtonText })
34367
34998
  ]
34368
34999
  }
34369
35000
  ),
@@ -34641,7 +35272,7 @@ class PrimeStyleTryonErrorBoundary extends reactExports.Component {
34641
35272
  function PrimeStyleTryon(props) {
34642
35273
  return /* @__PURE__ */ jsxRuntimeExports.jsx(PrimeStyleTryonErrorBoundary, { ...props });
34643
35274
  }
34644
- const STYLES = `
35275
+ const SIZE_GUIDE_STYLES = `
34645
35276
  .ps-sg-btn {
34646
35277
  display: inline-flex;
34647
35278
  align-items: center;
@@ -34804,7 +35435,7 @@ function injectStyles() {
34804
35435
  if (stylesInjected) return;
34805
35436
  const tag = document.createElement("style");
34806
35437
  tag.id = "ps-sg-styles";
34807
- tag.textContent = STYLES;
35438
+ tag.textContent = SIZE_GUIDE_STYLES;
34808
35439
  document.head.appendChild(tag);
34809
35440
  stylesInjected = true;
34810
35441
  }
@@ -34996,10 +35627,112 @@ function installProductViewTracking() {
34996
35627
  roots.forEach((r2) => maybeFireProductView(r2));
34997
35628
  }
34998
35629
  const TAG = "[primestyle-tryon]";
34999
- console.log(`${TAG} bundle loaded — version 5.7.x storefront entry`);
35630
+ const SHADOW_STYLE_ATTR = "data-primestyle-sdk";
35631
+ const DOCUMENT_STYLE_ATTR = "data-primestyle-sdk-document";
35632
+ const SHADOW_MOUNT_ATTR = "data-primestyle-mount";
35633
+ const PORTAL_HOST_ATTR = "data-primestyle-portal-host";
35634
+ const PORTAL_MOUNT_ATTR = "data-primestyle-portal-mount";
35635
+ const SDK_CSS = `${STYLES}
35636
+
35637
+ ${SIZE_GUIDE_STYLES}`;
35638
+ console.log(`${TAG} storefront bundle loaded`);
35000
35639
  installCartHook();
35001
35640
  installProductViewTracking();
35002
35641
  const MOUNTED = /* @__PURE__ */ new WeakMap();
35642
+ const MOUNT_SIGNATURES = /* @__PURE__ */ new WeakMap();
35643
+ const MOUNTING = /* @__PURE__ */ new WeakSet();
35644
+ function ensureDocumentStyles() {
35645
+ if (typeof document === "undefined" || !document.head) return;
35646
+ let styleTag = document.head.querySelector(`style[${DOCUMENT_STYLE_ATTR}]`);
35647
+ if (!styleTag) {
35648
+ styleTag = document.createElement("style");
35649
+ styleTag.setAttribute(DOCUMENT_STYLE_ATTR, "true");
35650
+ document.head.appendChild(styleTag);
35651
+ }
35652
+ if (styleTag.textContent !== SDK_CSS) {
35653
+ styleTag.textContent = SDK_CSS;
35654
+ }
35655
+ }
35656
+ function getPortalHost() {
35657
+ if (typeof document === "undefined" || !document.body) return void 0;
35658
+ let portalHost = document.querySelector(`[${PORTAL_HOST_ATTR}]`);
35659
+ if (!portalHost) {
35660
+ portalHost = document.createElement("div");
35661
+ portalHost.setAttribute(PORTAL_HOST_ATTR, "true");
35662
+ document.body.appendChild(portalHost);
35663
+ }
35664
+ portalHost.style.setProperty("display", "block", "important");
35665
+ portalHost.style.setProperty("position", "fixed", "important");
35666
+ portalHost.style.setProperty("inset", "0", "important");
35667
+ portalHost.style.setProperty("width", "100vw", "important");
35668
+ portalHost.style.setProperty("height", "100vh", "important");
35669
+ portalHost.style.setProperty("z-index", "2147483647", "important");
35670
+ portalHost.style.setProperty("visibility", "visible", "important");
35671
+ portalHost.style.setProperty("opacity", "1", "important");
35672
+ portalHost.style.setProperty("pointer-events", "none", "important");
35673
+ portalHost.style.setProperty("transform", "none", "important");
35674
+ portalHost.style.setProperty("margin", "0", "important");
35675
+ portalHost.style.setProperty("padding", "0", "important");
35676
+ if (typeof portalHost.attachShadow === "function") {
35677
+ try {
35678
+ const shadow = portalHost.shadowRoot || portalHost.attachShadow({ mode: "open" });
35679
+ let styleTag = shadow.querySelector(`style[${SHADOW_STYLE_ATTR}]`);
35680
+ if (!styleTag) {
35681
+ styleTag = document.createElement("style");
35682
+ styleTag.setAttribute(SHADOW_STYLE_ATTR, "true");
35683
+ shadow.appendChild(styleTag);
35684
+ }
35685
+ if (styleTag.textContent !== SDK_CSS) {
35686
+ styleTag.textContent = SDK_CSS;
35687
+ }
35688
+ let portalMount = shadow.querySelector(`[${PORTAL_MOUNT_ATTR}]`);
35689
+ if (!portalMount) {
35690
+ portalMount = document.createElement("div");
35691
+ portalMount.setAttribute(PORTAL_MOUNT_ATTR, "true");
35692
+ portalMount.className = "ps-tryon-portal-mount";
35693
+ shadow.appendChild(portalMount);
35694
+ }
35695
+ portalMount.style.setProperty("display", "block", "important");
35696
+ portalMount.style.setProperty("width", "100%", "important");
35697
+ portalMount.style.setProperty("height", "100%", "important");
35698
+ portalMount.style.setProperty("pointer-events", "none", "important");
35699
+ return portalMount;
35700
+ } catch (err) {
35701
+ console.warn(`${TAG} portal shadow DOM mount failed; falling back to page DOM`, err);
35702
+ }
35703
+ }
35704
+ ensureDocumentStyles();
35705
+ return portalHost;
35706
+ }
35707
+ function createShadowMountTarget(el2) {
35708
+ if (!(el2 instanceof HTMLElement) || typeof el2.attachShadow !== "function") {
35709
+ return { mountTarget: el2 };
35710
+ }
35711
+ try {
35712
+ const shadow = el2.shadowRoot || el2.attachShadow({ mode: "open" });
35713
+ let styleTag = shadow.querySelector(`style[${SHADOW_STYLE_ATTR}]`);
35714
+ if (!styleTag) {
35715
+ styleTag = document.createElement("style");
35716
+ styleTag.setAttribute(SHADOW_STYLE_ATTR, "true");
35717
+ shadow.appendChild(styleTag);
35718
+ }
35719
+ if (styleTag.textContent !== SDK_CSS) {
35720
+ styleTag.textContent = SDK_CSS;
35721
+ }
35722
+ let mountTarget = shadow.querySelector(`[${SHADOW_MOUNT_ATTR}]`);
35723
+ if (!mountTarget) {
35724
+ mountTarget = document.createElement("div");
35725
+ mountTarget.setAttribute(SHADOW_MOUNT_ATTR, "true");
35726
+ mountTarget.className = "ps-tryon-shadow-mount";
35727
+ shadow.appendChild(mountTarget);
35728
+ }
35729
+ el2.setAttribute("data-primestyle-shadow", "true");
35730
+ return { mountTarget, portalContainer: getPortalHost() ?? document.body };
35731
+ } catch (err) {
35732
+ console.warn(`${TAG} shadow DOM mount failed; falling back to page DOM`, err);
35733
+ return { mountTarget: el2 };
35734
+ }
35735
+ }
35003
35736
  function readDataAttrs(el2) {
35004
35737
  const out = {};
35005
35738
  for (const attr of Array.from(el2.attributes)) {
@@ -35018,6 +35751,22 @@ function parseJsonAttr(raw, fallback) {
35018
35751
  return fallback;
35019
35752
  }
35020
35753
  }
35754
+ function buildMountSignature(data) {
35755
+ const relevant = {};
35756
+ for (const key of Object.keys(data).sort()) {
35757
+ relevant[key] = data[key];
35758
+ }
35759
+ return JSON.stringify(relevant);
35760
+ }
35761
+ function resolveProductUrl(raw) {
35762
+ const source = raw || (typeof window !== "undefined" ? window.location.href : "");
35763
+ if (!source) return void 0;
35764
+ try {
35765
+ return new URL(source, window.location.origin).href;
35766
+ } catch {
35767
+ return source;
35768
+ }
35769
+ }
35021
35770
  function buildPropsFromDataAttrs(data) {
35022
35771
  const props = {
35023
35772
  apiUrl: data.proxyUrl || data.apiUrl || "",
@@ -35027,14 +35776,20 @@ function buildPropsFromDataAttrs(data) {
35027
35776
  apiKey: data.apiKey,
35028
35777
  productId: data.productId,
35029
35778
  productTitle: data.productTitle,
35779
+ productUrl: resolveProductUrl(data.productUrl),
35030
35780
  productImage: data.productImage,
35031
- productCarouselItems: parseJsonAttr(data.productCarouselItems, void 0),
35781
+ productImages: parseJsonAttr(data.productImages, void 0),
35782
+ productCarouselItems: parseJsonAttr(
35783
+ data.productCarouselItems,
35784
+ void 0
35785
+ ),
35032
35786
  productDescription: data.productDescription,
35033
35787
  productGender: data.productGender,
35034
35788
  productType: data.productType,
35035
35789
  productVendor: data.productVendor,
35036
35790
  productTags: data.productTags ? data.productTags.split(",").map((t2) => t2.trim()).filter(Boolean) : void 0,
35037
35791
  buttonText: data.buttonText || "Find Your Size",
35792
+ limitOneColorTryOnPerProduct: data.limitOneColorTryOnPerProduct === "true",
35038
35793
  locale: data.locale,
35039
35794
  sizeGuideData: parseJsonAttr(data.cachedSizeguide, void 0),
35040
35795
  sizingCountry: data.sizingCountry,
@@ -35071,22 +35826,39 @@ async function fetchSizeGuideForProduct(proxyUrl, productId) {
35071
35826
  }
35072
35827
  }
35073
35828
  async function mount(el2) {
35074
- if (MOUNTED.has(el2)) {
35075
- console.log(`${TAG} already mounted on`, el2);
35829
+ const data = readDataAttrs(el2);
35830
+ const signature = buildMountSignature(data);
35831
+ const existingRoot = MOUNTED.get(el2);
35832
+ if (existingRoot) {
35833
+ if (MOUNT_SIGNATURES.get(el2) === signature) {
35834
+ console.log(`${TAG} already mounted on`, el2);
35835
+ return;
35836
+ }
35837
+ console.log(`${TAG} data changed; remounting on`, el2);
35838
+ try {
35839
+ existingRoot.unmount();
35840
+ } catch (err) {
35841
+ console.warn(`${TAG} previous React root failed to unmount`, err);
35842
+ }
35843
+ MOUNTED.delete(el2);
35844
+ MOUNT_SIGNATURES.delete(el2);
35845
+ }
35846
+ if (MOUNTING.has(el2)) {
35847
+ console.log(`${TAG} mount already in progress on`, el2);
35076
35848
  return;
35077
35849
  }
35850
+ MOUNTING.add(el2);
35078
35851
  console.log(`${TAG} mounting on element`, el2);
35079
- const data = readDataAttrs(el2);
35080
35852
  console.log(`${TAG} read data attributes`, data);
35081
35853
  const props = buildPropsFromDataAttrs(data);
35082
- const hadCachedSizeguide = !!data.cachedSizeguide;
35854
+ const shouldRenderStandaloneSizeGuide = !!data.cachedSizeguide && data.disableSizeGuideButton !== "true";
35083
35855
  if (!props.sizeGuideData && props.productId && props.apiUrl) {
35084
35856
  const fetched = await fetchSizeGuideForProduct(props.apiUrl, props.productId);
35085
35857
  if (fetched) {
35086
35858
  props.sizeGuideData = fetched;
35087
35859
  }
35088
35860
  }
35089
- if (hadCachedSizeguide && props.sizeGuideData) {
35861
+ if (shouldRenderStandaloneSizeGuide && props.sizeGuideData) {
35090
35862
  try {
35091
35863
  const buttonStyles = props.buttonStyles;
35092
35864
  createSizeGuideButton(el2, props.sizeGuideData, {
@@ -35098,13 +35870,22 @@ async function mount(el2) {
35098
35870
  }
35099
35871
  }
35100
35872
  try {
35101
- const root = createRoot(el2);
35102
- root.render(reactExports.createElement(PrimeStyleTryon, props));
35873
+ const { mountTarget, portalContainer } = createShadowMountTarget(el2);
35874
+ const root = createRoot(mountTarget);
35875
+ root.render(
35876
+ reactExports.createElement(PrimeStyleTryon, {
35877
+ ...props,
35878
+ portalContainer
35879
+ })
35880
+ );
35103
35881
  MOUNTED.set(el2, root);
35882
+ MOUNT_SIGNATURES.set(el2, signature);
35104
35883
  console.log(`${TAG} ✓ mounted React component`);
35105
35884
  maybeFireProductView(el2);
35106
35885
  } catch (err) {
35107
35886
  console.error(`${TAG} ✗ React mount failed`, err);
35887
+ } finally {
35888
+ MOUNTING.delete(el2);
35108
35889
  }
35109
35890
  }
35110
35891
  function mountAll() {