@primestyleai/tryon 3.19.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -311,6 +311,9 @@ const en = {
311
311
  "Your size in other countries": "Your size in other countries",
312
312
  "Showing fit for size": "Showing fit for size",
313
313
  "Back to": "Back to",
314
+ "Edit values": "Edit values",
315
+ "Based on your updated measurements, size": "Based on your updated measurements, size",
316
+ "may be a better fit": "may be a better fit",
314
317
  "Fit Analysis": "Fit Analysis",
315
318
  "Show more": "Show more",
316
319
  "Done": "Done",
@@ -1,5 +1,5 @@
1
- import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-DmAF7P54.js";
2
- import { P, b, T, d, r } from "./index-DmAF7P54.js";
1
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-aIBOmApE.js";
2
+ import { P, b, T, d, r } from "./index-aIBOmApE.js";
3
3
  function detectProductImage() {
4
4
  const ogImage = document.querySelector(
5
5
  'meta[property="og:image"]'
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useMemo, useRef, useCallback } from "react";
4
- import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage, P as PrimeStyleError, L as LOCALE_LABELS, b as SUPPORTED_LOCALES } from "../index-DmAF7P54.js";
4
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage, P as PrimeStyleError, L as LOCALE_LABELS, b as SUPPORTED_LOCALES } from "../index-aIBOmApE.js";
5
5
  const HEADER_ALIASES = {
6
6
  // ── Size label columns (skipped during field derivation) ──
7
7
  size: "__size__",
@@ -406,6 +406,26 @@ const FALLBACK_FIELDS_MALE = [
406
406
  { key: "inseam", label: "Inseam", required: false, unit: "cm", placeholder: "e.g. 81", category: "body" },
407
407
  { key: "footLengthCm", label: "Foot length", required: false, unit: "cm", placeholder: "e.g. 27", category: "shoe" }
408
408
  ];
409
+ const SIZE_CONVERSIONS = {
410
+ "XXS": { US: "XXS", UK: "4", EU: "30", IT: "36", FR: "32", DE: "30", JP: "3", KR: "40", AU: "4", BR: "PP" },
411
+ "XS": { US: "XS", UK: "6", EU: "32", IT: "38", FR: "34", DE: "32", JP: "5", KR: "44", AU: "6", BR: "PP" },
412
+ "S": { US: "S", UK: "8", EU: "36", IT: "42", FR: "38", DE: "36", JP: "9", KR: "55", AU: "10", BR: "P" },
413
+ "M": { US: "M", UK: "10", EU: "38", IT: "44", FR: "40", DE: "38", JP: "11", KR: "66", AU: "12", BR: "M" },
414
+ "L": { US: "L", UK: "12", EU: "40", IT: "46", FR: "42", DE: "40", JP: "13", KR: "77", AU: "14", BR: "G" },
415
+ "XL": { US: "XL", UK: "14", EU: "42", IT: "48", FR: "44", DE: "42", JP: "15", KR: "88", AU: "16", BR: "GG" },
416
+ "XXL": { US: "XXL", UK: "16", EU: "44", IT: "50", FR: "46", DE: "44", JP: "17", KR: "99", AU: "18", BR: "XG" },
417
+ "XXXL": { US: "XXXL", UK: "18", EU: "46", IT: "52", FR: "48", DE: "46", JP: "19", KR: "100", AU: "20", BR: "EG" },
418
+ // Numeric sizes (EU-based)
419
+ "34": { US: "XS", UK: "6", EU: "34", IT: "38", FR: "34", DE: "34", JP: "5", KR: "44", AU: "6" },
420
+ "36": { US: "S", UK: "8", EU: "36", IT: "40", FR: "36", DE: "36", JP: "7", KR: "55", AU: "8" },
421
+ "38": { US: "M", UK: "10", EU: "38", IT: "42", FR: "38", DE: "38", JP: "9", KR: "66", AU: "10" },
422
+ "40": { US: "L", UK: "12", EU: "40", IT: "44", FR: "40", DE: "40", JP: "11", KR: "77", AU: "12" },
423
+ "42": { US: "XL", UK: "14", EU: "42", IT: "46", FR: "42", DE: "42", JP: "13", KR: "88", AU: "14" },
424
+ "44": { US: "XXL", UK: "16", EU: "44", IT: "48", FR: "44", DE: "44", JP: "15", KR: "99", AU: "16" },
425
+ "46": { US: "XXXL", UK: "18", EU: "46", IT: "50", FR: "46", DE: "46", JP: "17", KR: "100", AU: "18" },
426
+ "48": { US: "XXXL", UK: "20", EU: "48", IT: "52", FR: "48", DE: "48", JP: "19", KR: "105", AU: "20" },
427
+ "50": { US: "XXXL", UK: "22", EU: "50", IT: "54", FR: "50", DE: "50", JP: "21", KR: "110", AU: "22" }
428
+ };
409
429
  const STEP_LABELS = ["", "Welcome", "Size", "Your Fit", "Try On"];
410
430
  const TOTAL_STEPS = 4;
411
431
  function detectLocale() {
@@ -433,6 +453,22 @@ function lbsToKg(lbs) {
433
453
  function ftInToCm(ft, inch) {
434
454
  return +(ft * 30.48 + inch * 2.54).toFixed(1);
435
455
  }
456
+ function SvgIcon({ d, size = 18, strokeWidth = 2 }) {
457
+ return /* @__PURE__ */ jsx(
458
+ "svg",
459
+ {
460
+ width: size,
461
+ height: size,
462
+ viewBox: "0 0 24 24",
463
+ fill: "none",
464
+ stroke: "currentColor",
465
+ strokeWidth,
466
+ strokeLinecap: "round",
467
+ strokeLinejoin: "round",
468
+ children: /* @__PURE__ */ jsx("path", { d })
469
+ }
470
+ );
471
+ }
436
472
  function CameraIcon({ size = 18 }) {
437
473
  return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
438
474
  /* @__PURE__ */ jsx("path", { d: "M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" }),
@@ -1472,8 +1508,11 @@ function PrimeStyleTryonInner({
1472
1508
  }
1473
1509
  function SizeResultView() {
1474
1510
  const unitLbl = sizingUnit === "cm" ? t("cm") : t("in");
1511
+ const [editing, setEditing] = useState(false);
1475
1512
  const [editVals, setEditVals] = useState({});
1476
1513
  const [compareSize, setCompareSize] = useState("");
1514
+ const recSize = sizingResult?.recommendedSize || "";
1515
+ const selSize = compareSize || recSize;
1477
1516
  const sizeColIdx = useMemo(() => {
1478
1517
  if (!sizeGuide?.headers || !sizeGuide?.rows) return -1;
1479
1518
  const byName = sizeGuide.headers.findIndex((h) => /size|taglia|größe|taille/i.test(h.trim()));
@@ -1508,7 +1547,6 @@ function PrimeStyleTryonInner({
1508
1547
  }, [sizeGuide, sizeColIdx]);
1509
1548
  const fitRows = useMemo(() => {
1510
1549
  if (!sizingResult?.matchDetails?.length) return [];
1511
- compareSize || sizingResult.recommendedSize || "";
1512
1550
  return sizingResult.matchDetails.map((m) => {
1513
1551
  const origNum = pNum(m.userValue);
1514
1552
  const edited = editVals[m.measurement];
@@ -1527,9 +1565,31 @@ function PrimeStyleTryonInner({
1527
1565
  return { area: m.measurement, userNum, chartLabel, fit };
1528
1566
  });
1529
1567
  }, [sizingResult, compareSize, editVals, chartRangeFor]);
1530
- const intlSizes = sizingResult?.internationalSizes || {};
1531
- const recSize = sizingResult?.recommendedSize || "";
1532
- const selSize = compareSize || recSize;
1568
+ const suggestedSize = useMemo(() => {
1569
+ if (!Object.keys(editVals).length || !sizingResult?.matchDetails?.length || !allSizes.length) return null;
1570
+ let bestSize = "";
1571
+ let bestScore = -1;
1572
+ for (const size of allSizes) {
1573
+ let score = 0;
1574
+ for (const m of sizingResult.matchDetails) {
1575
+ const edited = editVals[m.measurement];
1576
+ const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : pNum(m.userValue);
1577
+ const alt = chartRangeFor(m.measurement, size);
1578
+ if (alt && userNum >= alt.min && userNum <= alt.max) score++;
1579
+ }
1580
+ if (score > bestScore) {
1581
+ bestScore = score;
1582
+ bestSize = size;
1583
+ }
1584
+ }
1585
+ return bestSize && bestSize !== recSize ? bestSize : null;
1586
+ }, [editVals, sizingResult, allSizes, recSize, chartRangeFor]);
1587
+ const allIntlSizes = useMemo(() => {
1588
+ const backendIntl = sizingResult?.internationalSizes || {};
1589
+ const upper = recSize.toUpperCase().trim();
1590
+ const fromTable = SIZE_CONVERSIONS[upper] || SIZE_CONVERSIONS[recSize] || {};
1591
+ return { ...fromTable, ...backendIntl };
1592
+ }, [sizingResult, recSize]);
1533
1593
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr", children: [
1534
1594
  sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-loading", children: [
1535
1595
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
@@ -1539,71 +1599,75 @@ function PrimeStyleTryonInner({
1539
1599
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero", children: [
1540
1600
  recSize && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: recSize }),
1541
1601
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-info", children: [
1542
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-title", children: [
1543
- t("Your Size"),
1544
- recSize ? `: ${recSize}` : ""
1545
- ] }),
1602
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-title", children: t("Your Size") }),
1546
1603
  /* @__PURE__ */ jsx("div", { className: `ps-tryon-sr-hero-conf ps-conf-${sizingResult.confidence}`, children: sizingResult.confidence === "high" ? t("High Confidence") : sizingResult.confidence === "medium" ? t("Medium Confidence") : t("Low Confidence") })
1547
1604
  ] })
1548
1605
  ] }),
1549
- Object.keys(intlSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1550
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Your size in other countries") }),
1551
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-primary", children: Object.entries(intlSizes).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-card", children: [
1606
+ suggestedSize && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-suggestion", children: [
1607
+ /* @__PURE__ */ jsx(SparkleIcon, { size: 14 }),
1608
+ /* @__PURE__ */ jsxs("span", { children: [
1609
+ t("Based on your updated measurements, size"),
1610
+ " ",
1611
+ /* @__PURE__ */ jsx("strong", { children: suggestedSize }),
1612
+ " ",
1613
+ t("may be a better fit")
1614
+ ] })
1615
+ ] }),
1616
+ Object.keys(allIntlSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1617
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-section-title", children: t("Your size in other countries") }),
1618
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-grid", children: Object.entries(allIntlSizes).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-card", children: [
1552
1619
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-val", children: val }),
1553
1620
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-code", children: code })
1554
1621
  ] }, code)) })
1555
1622
  ] }),
1556
- allSizes.length > 1 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-compare", children: [
1557
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Compare with another size") }),
1558
- /* @__PURE__ */ jsx("select", { className: "ps-tryon-sr-compare-select", value: selSize, onChange: (e) => setCompareSize(e.target.value), children: allSizes.map((s) => /* @__PURE__ */ jsxs("option", { value: s, children: [
1623
+ fitRows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit", children: [
1624
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-top", children: [
1625
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-section-title", children: t("Fit Analysis") }),
1626
+ /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-edit-btn", onClick: () => setEditing(!editing), children: [
1627
+ /* @__PURE__ */ jsx(SvgIcon, { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7", size: 12 }),
1628
+ editing ? t("Done") : t("Edit values")
1629
+ ] })
1630
+ ] }),
1631
+ allSizes.length > 1 && /* @__PURE__ */ jsx("select", { className: "ps-tryon-sr-compare-select", value: selSize, onChange: (e) => setCompareSize(e.target.value), children: allSizes.map((s) => /* @__PURE__ */ jsxs("option", { value: s, children: [
1559
1632
  s,
1560
1633
  s === recSize ? ` ★ ${t("recommended")}` : ""
1561
1634
  ] }, s)) }),
1562
- compareSize && compareSize !== recSize && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-compare-note", children: [
1563
- t("Showing fit for size"),
1564
- " ",
1565
- /* @__PURE__ */ jsx("strong", { children: compareSize }),
1566
- /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-compare-reset", onClick: () => setCompareSize(""), children: [
1567
- t("Back to"),
1568
- " ",
1569
- recSize
1570
- ] })
1571
- ] })
1572
- ] }),
1573
- fitRows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit", children: [
1574
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Fit Analysis") }),
1575
- fitRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-fit-card ps-fit-${row.fit}`, children: [
1576
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-card-top", children: [
1577
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-area", children: row.area }),
1578
- /* @__PURE__ */ jsx("span", { className: `ps-tryon-sr-fit-badge ps-fit-${row.fit}`, children: row.fit === "good" ? `✓ ${t("within range")}` : row.fit === "tight" ? `↑ ${t("may be snug")}` : `↓ ${t("may be loose")}` })
1635
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fit-cards", children: fitRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-fc ps-fit-${row.fit}`, children: [
1636
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-head", children: [
1637
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-area", children: row.area }),
1638
+ /* @__PURE__ */ jsx("span", { className: `ps-tryon-sr-fc-badge ps-fit-${row.fit}`, children: row.fit === "good" ? `✓ ${t("within range")}` : row.fit === "tight" ? `↑ ${t("may be snug")}` : `↓ ${t("may be loose")}` })
1579
1639
  ] }),
1580
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-card-bottom", children: [
1581
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val", children: [
1582
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-val-label", children: t("You") }),
1583
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val-input-wrap", children: [
1640
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-body", children: [
1641
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1642
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fc-label", children: t("You") }),
1643
+ editing ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-edit", children: [
1584
1644
  /* @__PURE__ */ jsx(
1585
1645
  "input",
1586
1646
  {
1587
1647
  type: "number",
1588
- className: "ps-tryon-sr-fit-input",
1648
+ className: "ps-tryon-sr-fc-input",
1589
1649
  value: editVals[row.area] !== void 0 ? editVals[row.area] : row.userNum,
1590
1650
  onChange: (e) => setEditVals((prev) => ({ ...prev, [row.area]: e.target.value }))
1591
1651
  }
1592
1652
  ),
1593
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-unit", children: unitLbl })
1653
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-unit", children: unitLbl })
1654
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-value", children: [
1655
+ row.userNum,
1656
+ " ",
1657
+ unitLbl
1594
1658
  ] })
1595
1659
  ] }),
1596
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val", children: [
1597
- /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-fit-val-label", children: [
1660
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1661
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-label", children: [
1598
1662
  t("Chart"),
1599
1663
  " (",
1600
1664
  selSize,
1601
1665
  ")"
1602
1666
  ] }),
1603
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-val-text", children: row.chartLabel })
1667
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fc-value", children: row.chartLabel })
1604
1668
  ] })
1605
1669
  ] })
1606
- ] }, i))
1670
+ ] }, i)) })
1607
1671
  ] }),
1608
1672
  fitRows.length === 0 && sizingResult.reasoning && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-reasoning", children: /* @__PURE__ */ jsx("p", { children: sizingResult.reasoning }) }),
1609
1673
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-ctas", children: [
@@ -1888,7 +1952,7 @@ const STYLES = `
1888
1952
  .ps-tryon-modal {
1889
1953
  background: var(--ps-modal-bg, #111211); color: var(--ps-modal-color, #fff);
1890
1954
  border-radius: var(--ps-modal-radius, 0.83vw); width: var(--ps-modal-width, 100%);
1891
- max-width: var(--ps-modal-max-width, 27vw); max-height: 92vh; overflow-y: auto;
1955
+ max-width: var(--ps-modal-max-width, 32vw); max-height: 92vh; overflow-y: auto;
1892
1956
  font-family: var(--ps-modal-font, system-ui, -apple-system, sans-serif);
1893
1957
  box-shadow: 0 1.3vw 2.6vw rgba(0,0,0,0.4); animation: ps-slide-up 0.3s ease;
1894
1958
  scrollbar-width: thin; scrollbar-color: #333 transparent;
@@ -2275,62 +2339,59 @@ const STYLES = `
2275
2339
  .ps-tryon-btn-retry:hover { background: rgba(255,255,255,0.12); }
2276
2340
 
2277
2341
  /* ── Size Result (redesigned) ── */
2278
- .ps-tryon-sr { display: flex; flex-direction: column; gap: 1.1vw; }
2279
- .ps-tryon-sr-loading { text-align: center; padding: 2vw 0; }
2280
- .ps-tryon-sr-loading p { font-size: 0.83vw; color: #999; margin-top: 0.5vw; }
2342
+ .ps-tryon-sr { display: flex; flex-direction: column; gap: 1.25vw; }
2343
+ .ps-tryon-sr-loading { text-align: center; padding: 3vw 0; }
2344
+ .ps-tryon-sr-loading p { font-size: 0.83vw; color: #666; margin-top: 0.6vw; }
2281
2345
  .ps-tryon-size-loading-spinner {
2282
- width: 2vw; height: 2vw; border: 3px solid #333;
2346
+ width: 1.8vw; height: 1.8vw; border: 2px solid #282828;
2283
2347
  border-top-color: #bb945c; border-radius: 50%;
2284
- animation: ps-spin 0.8s linear infinite; margin: 0 auto;
2348
+ animation: ps-spin 0.7s linear infinite; margin: 0 auto;
2285
2349
  }
2286
2350
  @keyframes ps-spin { to { transform: rotate(360deg); } }
2287
2351
 
2288
2352
  /* Hero */
2289
2353
  .ps-tryon-sr-hero {
2290
- display: flex; align-items: center; gap: 1vw; padding: 1vw 1.2vw;
2291
- background: linear-gradient(135deg, rgba(187,148,92,0.08), rgba(187,148,92,0.02));
2292
- border: 1.5px solid rgba(187,148,92,0.25); border-radius: 0.83vw;
2354
+ display: flex; align-items: center; gap: 1vw; padding: 1.1vw 1.3vw;
2355
+ background: linear-gradient(135deg, rgba(187,148,92,0.06), rgba(187,148,92,0.01));
2356
+ border: 1px solid rgba(187,148,92,0.2); border-radius: 0.83vw;
2293
2357
  }
2294
2358
  .ps-tryon-sr-hero-badge {
2295
- min-width: 3.5vw; height: 3.5vw; display: flex; align-items: center; justify-content: center;
2359
+ min-width: 3.2vw; height: 3.2vw; display: flex; align-items: center; justify-content: center;
2296
2360
  background: linear-gradient(135deg, #bb945c, #d6ba7d); color: #111;
2297
- font-size: 1.5vw; font-weight: 800; border-radius: 0.73vw; letter-spacing: -0.02em;
2298
- padding: 0 0.8vw; box-shadow: 0 0.4vw 1.2vw rgba(187,148,92,0.25);
2361
+ font-size: 1.35vw; font-weight: 800; border-radius: 0.63vw; letter-spacing: -0.02em;
2362
+ padding: 0 0.73vw; box-shadow: 0 0.3vw 1vw rgba(187,148,92,0.3);
2299
2363
  }
2300
2364
  .ps-tryon-sr-hero-info { flex: 1; }
2301
- .ps-tryon-sr-hero-title { font-size: 1.04vw; font-weight: 700; color: #fff; margin-bottom: 0.15vw; }
2302
- .ps-tryon-sr-hero-conf { font-size: 0.78vw; font-weight: 600; }
2365
+ .ps-tryon-sr-hero-title { font-size: 1vw; font-weight: 700; color: #fff; margin-bottom: 0.1vw; }
2366
+ .ps-tryon-sr-hero-conf { font-size: 0.73vw; font-weight: 600; }
2303
2367
  .ps-conf-high { color: #4ade80; } .ps-conf-medium { color: #bb945c; } .ps-conf-low { color: #ef4444; }
2304
2368
 
2369
+ /* Suggestion banner */
2370
+ .ps-tryon-sr-suggestion {
2371
+ display: flex; align-items: center; gap: 0.52vw;
2372
+ padding: 0.63vw 0.83vw; border-radius: 0.52vw;
2373
+ background: rgba(187,148,92,0.08); border: 1px solid rgba(187,148,92,0.2);
2374
+ font-size: 0.73vw; color: #d6ba7d; animation: ps-fade-up 0.3s ease both;
2375
+ }
2376
+ .ps-tryon-sr-suggestion svg { stroke: #bb945c; flex-shrink: 0; }
2377
+ .ps-tryon-sr-suggestion strong { color: #fff; }
2378
+
2379
+ /* Section titles */
2380
+ .ps-tryon-sr-section-title { font-size: 0.73vw; font-weight: 700; color: #666; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.52vw; }
2381
+
2305
2382
  /* International sizes */
2306
2383
  .ps-tryon-sr-intl { }
2307
- .ps-tryon-sr-label { font-size: 0.78vw; font-weight: 700; color: #999; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 0.52vw; }
2308
- .ps-tryon-sr-label-hint { font-weight: 400; text-transform: none; letter-spacing: 0; color: #666; font-style: italic; }
2309
- .ps-tryon-sr-intl-primary { display: flex; flex-wrap: wrap; gap: 0.42vw; margin-bottom: 0.52vw; }
2384
+ .ps-tryon-sr-intl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(3.8vw, 1fr)); gap: 0.42vw; }
2310
2385
  .ps-tryon-sr-intl-card {
2311
- flex: 1; min-width: 3.5vw; display: flex; flex-direction: column; align-items: center;
2312
- padding: 0.57vw 0.42vw; border: 1.5px solid #333; border-radius: 0.63vw;
2313
- background: #1a1b1a; transition: border-color 0.2s;
2386
+ display: flex; flex-direction: column; align-items: center;
2387
+ padding: 0.62vw 0.36vw; border: 1px solid #282828; border-radius: 0.52vw;
2388
+ background: #161616; transition: all 0.2s;
2314
2389
  }
2315
- .ps-tryon-sr-intl-card:hover { border-color: #555; }
2316
- .ps-tryon-sr-intl-card-val { font-size: 1.04vw; font-weight: 800; color: #fff; line-height: 1.2; }
2317
- .ps-tryon-sr-intl-card-code { font-size: 0.57vw; font-weight: 700; color: #666; text-transform: uppercase; letter-spacing: 0.08em; margin-top: 0.1vw; }
2318
-
2319
- .ps-tryon-sr-intl-more { }
2320
- .ps-tryon-sr-intl-more-btn {
2321
- font-size: 0.73vw; color: #bb945c; font-weight: 600; cursor: pointer;
2322
- list-style: none; margin-bottom: 0.42vw; font-family: inherit;
2323
- }
2324
- .ps-tryon-sr-intl-more-btn::-webkit-details-marker { display: none; }
2325
- .ps-tryon-sr-intl-more-btn::before { content: "▸ "; }
2326
- .ps-tryon-sr-intl-more[open] .ps-tryon-sr-intl-more-btn::before { content: "▾ "; }
2390
+ .ps-tryon-sr-intl-card:hover { border-color: #444; background: #1c1c1c; }
2391
+ .ps-tryon-sr-intl-card-val { font-size: 1.1vw; font-weight: 800; color: #fff; line-height: 1.15; }
2392
+ .ps-tryon-sr-intl-card-code { font-size: 0.52vw; font-weight: 700; color: #555; text-transform: uppercase; letter-spacing: 0.1em; margin-top: 0.15vw; }
2327
2393
 
2328
- .ps-tryon-sr-intl-grid { display: flex; flex-wrap: wrap; gap: 0.42vw; }
2329
- .ps-tryon-sr-intl-item {
2330
- display: flex; align-items: center; border: 1.5px solid #333; border-radius: 0.52vw; overflow: hidden;
2331
- }
2332
- .ps-tryon-sr-intl-code { padding: 0.42vw 0.57vw; font-size: 0.68vw; color: #999; font-weight: 700; background: rgba(255,255,255,0.03); letter-spacing: 0.04em; }
2333
- .ps-tryon-sr-intl-val { padding: 0.42vw 0.68vw; font-size: 0.83vw; color: #fff; font-weight: 700; }
2394
+ /* (intl grid uses .ps-tryon-sr-intl-grid defined above) */
2334
2395
 
2335
2396
  /* Size selector */
2336
2397
  .ps-tryon-sr-sizes { }
@@ -2356,44 +2417,61 @@ const STYLES = `
2356
2417
  .ps-tryon-sr-comparing { font-size: 0.73vw; color: #bb945c; margin-top: 0.42vw; }
2357
2418
  .ps-tryon-sr-comparing strong { color: #d6ba7d; }
2358
2419
 
2359
- /* Fit analysis cards */
2360
- .ps-tryon-sr-fit { display: flex; flex-direction: column; gap: 0.52vw; }
2361
- .ps-tryon-sr-fit-card {
2362
- border: 1.5px solid #333; border-radius: 0.63vw; overflow: hidden; transition: border-color 0.2s;
2363
- }
2364
- .ps-tryon-sr-fit-card.ps-fit-good { border-left: 3px solid #4ade80; }
2365
- .ps-tryon-sr-fit-card.ps-fit-tight { border-left: 3px solid #f59e0b; }
2366
- .ps-tryon-sr-fit-card.ps-fit-loose { border-left: 3px solid #60a5fa; }
2367
- .ps-tryon-sr-fit-card-top {
2368
- display: flex; align-items: center; justify-content: space-between;
2369
- padding: 0.52vw 0.83vw; background: #1a1b1a;
2420
+ /* Fit analysis */
2421
+ .ps-tryon-sr-fit { }
2422
+ .ps-tryon-sr-fit-top {
2423
+ display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.52vw;
2370
2424
  }
2371
- .ps-tryon-sr-fit-area { font-size: 0.83vw; font-weight: 600; color: #fff; }
2372
- .ps-tryon-sr-fit-card-bottom {
2373
- display: flex; gap: 1vw; padding: 0.52vw 0.83vw;
2425
+ .ps-tryon-sr-edit-btn {
2426
+ display: inline-flex; align-items: center; gap: 0.31vw;
2427
+ padding: 0.31vw 0.73vw; border: 1px solid rgba(187,148,92,0.4); border-radius: 0.42vw;
2428
+ background: rgba(187,148,92,0.06); color: #bb945c; font-size: 0.68vw; font-weight: 600;
2429
+ cursor: pointer; font-family: inherit; transition: all 0.2s;
2374
2430
  }
2375
- .ps-tryon-sr-fit-val { flex: 1; }
2376
- .ps-tryon-sr-fit-val-label { font-size: 0.57vw; font-weight: 700; color: #666; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 0.21vw; display: block; }
2377
- .ps-tryon-sr-fit-val-input-wrap { display: flex; align-items: center; gap: 0.26vw; }
2378
- .ps-tryon-sr-fit-val-text { font-size: 0.83vw; font-weight: 600; color: #ccc; }
2431
+ .ps-tryon-sr-edit-btn:hover { background: rgba(187,148,92,0.12); border-color: #bb945c; }
2432
+ .ps-tryon-sr-edit-btn svg { stroke: currentColor; }
2379
2433
 
2380
- .ps-tryon-sr-fit-input {
2381
- width: 4vw; padding: 0.31vw 0.42vw; border: 1.5px solid #444; border-radius: 0.36vw;
2382
- background: #0c0c0d; color: #fff; font-size: 0.83vw; font-weight: 600; font-family: inherit;
2383
- outline: none; text-align: center; -moz-appearance: textfield;
2434
+ .ps-tryon-sr-fit-cards { display: flex; flex-direction: column; gap: 0.42vw; }
2435
+
2436
+ .ps-tryon-sr-fc {
2437
+ border: 1px solid #282828; border-radius: 0.63vw; overflow: hidden;
2438
+ transition: border-color 0.2s;
2384
2439
  }
2385
- .ps-tryon-sr-fit-input::-webkit-outer-spin-button,
2386
- .ps-tryon-sr-fit-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2387
- .ps-tryon-sr-fit-input:focus { border-color: #bb945c; background: #1a1b1a; }
2388
- .ps-tryon-sr-fit-unit { font-size: 0.68vw; color: #666; }
2440
+ .ps-tryon-sr-fc.ps-fit-good { border-left: 3px solid #4ade80; }
2441
+ .ps-tryon-sr-fc.ps-fit-tight { border-left: 3px solid #f59e0b; }
2442
+ .ps-tryon-sr-fc.ps-fit-loose { border-left: 3px solid #60a5fa; }
2389
2443
 
2390
- .ps-tryon-sr-fit-badge {
2391
- display: inline-flex; align-items: center; gap: 0.26vw; padding: 0.26vw 0.57vw;
2392
- border-radius: 0.36vw; font-size: 0.68vw; font-weight: 700; white-space: nowrap;
2444
+ .ps-tryon-sr-fc-head {
2445
+ display: flex; align-items: center; justify-content: space-between;
2446
+ padding: 0.57vw 0.83vw; background: #161616;
2393
2447
  }
2394
- .ps-tryon-sr-fit-badge.ps-fit-good { background: rgba(74,222,128,0.1); color: #4ade80; }
2395
- .ps-tryon-sr-fit-badge.ps-fit-tight { background: rgba(245,158,11,0.1); color: #f59e0b; }
2396
- .ps-tryon-sr-fit-badge.ps-fit-loose { background: rgba(96,165,250,0.1); color: #60a5fa; }
2448
+ .ps-tryon-sr-fc-area { font-size: 0.83vw; font-weight: 700; color: #fff; }
2449
+
2450
+ .ps-tryon-sr-fc-badge {
2451
+ display: inline-flex; align-items: center; gap: 0.21vw; padding: 0.21vw 0.52vw;
2452
+ border-radius: 0.31vw; font-size: 0.63vw; font-weight: 700; white-space: nowrap;
2453
+ }
2454
+ .ps-tryon-sr-fc-badge.ps-fit-good { background: rgba(74,222,128,0.08); color: #4ade80; }
2455
+ .ps-tryon-sr-fc-badge.ps-fit-tight { background: rgba(245,158,11,0.08); color: #f59e0b; }
2456
+ .ps-tryon-sr-fc-badge.ps-fit-loose { background: rgba(96,165,250,0.08); color: #60a5fa; }
2457
+
2458
+ .ps-tryon-sr-fc-body {
2459
+ display: flex; gap: 1.5vw; padding: 0.52vw 0.83vw 0.62vw;
2460
+ }
2461
+ .ps-tryon-sr-fc-col { flex: 1; }
2462
+ .ps-tryon-sr-fc-label { font-size: 0.52vw; font-weight: 700; color: #555; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 0.15vw; }
2463
+ .ps-tryon-sr-fc-value { font-size: 0.88vw; font-weight: 600; color: #ccc; }
2464
+ .ps-tryon-sr-fc-edit { display: flex; align-items: center; gap: 0.26vw; }
2465
+ .ps-tryon-sr-fc-input {
2466
+ width: 4.2vw; padding: 0.26vw 0.42vw; border: 1.5px solid #444; border-radius: 0.36vw;
2467
+ background: #0c0c0d; color: #fff; font-size: 0.88vw; font-weight: 600; font-family: inherit;
2468
+ outline: none; text-align: center; -moz-appearance: textfield;
2469
+ transition: border-color 0.2s, background 0.2s;
2470
+ }
2471
+ .ps-tryon-sr-fc-input::-webkit-outer-spin-button,
2472
+ .ps-tryon-sr-fc-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2473
+ .ps-tryon-sr-fc-input:focus { border-color: #bb945c; background: #1a1a1a; }
2474
+ .ps-tryon-sr-fc-unit { font-size: 0.63vw; color: #555; }
2397
2475
 
2398
2476
  /* Compare dropdown */
2399
2477
  .ps-tryon-sr-compare { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "3.19.0",
3
+ "version": "4.0.0",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",