@primestyleai/tryon 3.20.0 → 4.1.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.
@@ -312,6 +312,8 @@ const en = {
312
312
  "Showing fit for size": "Showing fit for size",
313
313
  "Back to": "Back to",
314
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",
315
317
  "Fit Analysis": "Fit Analysis",
316
318
  "Show more": "Show more",
317
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-Dr4MxT8W.js";
2
- import { P, b, T, d, r } from "./index-Dr4MxT8W.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-Dr4MxT8W.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__",
@@ -1511,15 +1511,26 @@ function PrimeStyleTryonInner({
1511
1511
  const [editing, setEditing] = useState(false);
1512
1512
  const [editVals, setEditVals] = useState({});
1513
1513
  const [compareSize, setCompareSize] = useState("");
1514
- const recSize = sizingResult?.recommendedSize || "";
1514
+ const cleanChart = (s) => s.replace(/\s*(cm|CM|in|IN|inches|mm|MM)\s*$/i, "").trim();
1515
+ const recSize = useMemo(() => {
1516
+ if (sizingResult?.recommendedSize) return sizingResult.recommendedSize;
1517
+ if (sizeGuide?.rows && sizeGuide.headers) {
1518
+ const sc = sizeGuide.headers.findIndex((h) => /size|taglia|größe|taille/i.test(h.trim()));
1519
+ const idx = sc >= 0 ? sc : 0;
1520
+ for (const row of sizeGuide.rows) {
1521
+ const label = row[idx]?.trim();
1522
+ if (label && /^(XXS|XS|S|M|L|XL|XXL|XXXL|\d{1,3})$/i.test(label)) return label;
1523
+ }
1524
+ }
1525
+ return "";
1526
+ }, [sizingResult, sizeGuide]);
1515
1527
  const selSize = compareSize || recSize;
1516
1528
  const sizeColIdx = useMemo(() => {
1517
1529
  if (!sizeGuide?.headers || !sizeGuide?.rows) return -1;
1518
1530
  const byName = sizeGuide.headers.findIndex((h) => /size|taglia|größe|taille/i.test(h.trim()));
1519
1531
  if (byName >= 0) return byName;
1520
1532
  for (let c = 0; c < sizeGuide.headers.length; c++) {
1521
- const vals = sizeGuide.rows.map((r) => r[c]?.trim() || "");
1522
- if (vals.some((v) => /^(XXS|XS|S|M|L|XL|XXL|XXXL|ONE SIZE|\d{1,2})$/i.test(v))) return c;
1533
+ if (sizeGuide.rows.some((r) => /^(XXS|XS|S|M|L|XL|XXL|XXXL|ONE SIZE|\d{1,2})$/i.test(r[c]?.trim() || ""))) return c;
1523
1534
  }
1524
1535
  return 0;
1525
1536
  }, [sizeGuide]);
@@ -1553,7 +1564,7 @@ function PrimeStyleTryonInner({
1553
1564
  const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : origNum;
1554
1565
  let { min: rMin, max: rMax } = pRange(m.chartRange);
1555
1566
  let chartLabel = m.chartRange;
1556
- if (compareSize && compareSize !== sizingResult.recommendedSize) {
1567
+ if (compareSize && compareSize !== recSize) {
1557
1568
  const alt = chartRangeFor(m.measurement, compareSize);
1558
1569
  if (alt) {
1559
1570
  chartLabel = alt.range;
@@ -1562,16 +1573,35 @@ function PrimeStyleTryonInner({
1562
1573
  }
1563
1574
  }
1564
1575
  const fit = userNum >= rMin && userNum <= rMax ? "good" : userNum < rMin ? "tight" : "loose";
1565
- return { area: m.measurement, userNum, chartLabel, fit };
1576
+ return { area: m.measurement, userNum, chartLabel: cleanChart(chartLabel), fit };
1566
1577
  });
1567
- }, [sizingResult, compareSize, editVals, chartRangeFor]);
1578
+ }, [sizingResult, compareSize, editVals, chartRangeFor, recSize]);
1579
+ const suggestedSize = useMemo(() => {
1580
+ if (!Object.keys(editVals).length || !sizingResult?.matchDetails?.length || !allSizes.length) return null;
1581
+ let bestSize = "";
1582
+ let bestScore = -1;
1583
+ for (const size of allSizes) {
1584
+ let score = 0;
1585
+ for (const m of sizingResult.matchDetails) {
1586
+ const edited = editVals[m.measurement];
1587
+ const userNum = edited !== void 0 && edited !== "" ? parseFloat(edited) : pNum(m.userValue);
1588
+ const alt = chartRangeFor(m.measurement, size);
1589
+ if (alt && userNum >= alt.min && userNum <= alt.max) score++;
1590
+ }
1591
+ if (score > bestScore) {
1592
+ bestScore = score;
1593
+ bestSize = size;
1594
+ }
1595
+ }
1596
+ return bestSize && bestSize !== recSize ? bestSize : null;
1597
+ }, [editVals, sizingResult, allSizes, recSize, chartRangeFor]);
1568
1598
  const allIntlSizes = useMemo(() => {
1569
1599
  const backendIntl = sizingResult?.internationalSizes || {};
1570
1600
  const upper = recSize.toUpperCase().trim();
1571
1601
  const fromTable = SIZE_CONVERSIONS[upper] || SIZE_CONVERSIONS[recSize] || {};
1572
- const merged = { ...fromTable, ...backendIntl };
1573
- return merged;
1602
+ return { ...fromTable, ...backendIntl };
1574
1603
  }, [sizingResult, recSize]);
1604
+ const confLabel = sizingResult?.confidence === "high" ? t("High Confidence") : sizingResult?.confidence === "medium" ? t("Medium Confidence") : t("Low Confidence");
1575
1605
  return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr", children: [
1576
1606
  sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-loading", children: [
1577
1607
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
@@ -1579,80 +1609,84 @@ function PrimeStyleTryonInner({
1579
1609
  ] }),
1580
1610
  sizingResult && /* @__PURE__ */ jsxs(Fragment, { children: [
1581
1611
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero", children: [
1582
- recSize && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: recSize }),
1612
+ recSize ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: recSize }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge ps-tryon-sr-hero-badge-icon", children: /* @__PURE__ */ jsx(RulerIcon, { size: 22 }) }),
1583
1613
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-info", children: [
1584
1614
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-title", children: t("Your Size") }),
1585
- /* @__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") })
1615
+ /* @__PURE__ */ jsx("div", { className: `ps-tryon-sr-hero-conf ps-conf-${sizingResult.confidence}`, children: confLabel })
1586
1616
  ] })
1587
1617
  ] }),
1618
+ suggestedSize && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-suggestion", onClick: () => {
1619
+ setCompareSize(suggestedSize);
1620
+ }, children: [
1621
+ /* @__PURE__ */ jsx(SparkleIcon, { size: 14 }),
1622
+ /* @__PURE__ */ jsxs("span", { children: [
1623
+ t("Based on your updated measurements, size"),
1624
+ " ",
1625
+ /* @__PURE__ */ jsx("strong", { children: suggestedSize }),
1626
+ " ",
1627
+ t("may be a better fit")
1628
+ ] }),
1629
+ /* @__PURE__ */ jsx(ArrowRightIcon, {})
1630
+ ] }),
1588
1631
  Object.keys(allIntlSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1589
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Your size in other countries") }),
1590
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-primary", children: Object.entries(allIntlSizes).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-card", children: [
1632
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-section-title", children: t("Your size in other countries") }),
1633
+ /* @__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: [
1591
1634
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-val", children: val }),
1592
1635
  /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-card-code", children: code })
1593
1636
  ] }, code)) })
1594
1637
  ] }),
1595
- allSizes.length > 1 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-compare", children: [
1596
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Compare with another size") }),
1597
- /* @__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: [
1598
- s,
1599
- s === recSize ? ` ★ ${t("recommended")}` : ""
1600
- ] }, s)) }),
1601
- compareSize && compareSize !== recSize && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-compare-note", children: [
1602
- t("Showing fit for size"),
1603
- " ",
1604
- /* @__PURE__ */ jsx("strong", { children: compareSize }),
1605
- /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-compare-reset", onClick: () => setCompareSize(""), children: [
1606
- t("Back to"),
1607
- " ",
1608
- recSize
1609
- ] })
1610
- ] })
1611
- ] }),
1612
1638
  fitRows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit", children: [
1613
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-header-row", children: [
1614
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-label", children: t("Fit Analysis") }),
1639
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-top", children: [
1640
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-section-title", children: t("Fit Analysis") }),
1615
1641
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-edit-btn", onClick: () => setEditing(!editing), children: [
1616
1642
  /* @__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 }),
1617
1643
  editing ? t("Done") : t("Edit values")
1618
1644
  ] })
1619
1645
  ] }),
1620
- fitRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-fit-card ps-fit-${row.fit}`, children: [
1621
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-card-top", children: [
1622
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-area", children: row.area }),
1623
- /* @__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")}` })
1646
+ 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: [
1647
+ s,
1648
+ s === recSize ? ` ★ ${t("recommended")}` : ""
1649
+ ] }, s)) }),
1650
+ /* @__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: [
1651
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-head", children: [
1652
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-area", children: row.area }),
1653
+ /* @__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")}` })
1624
1654
  ] }),
1625
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-card-bottom", children: [
1626
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val", children: [
1627
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-val-label", children: t("You") }),
1628
- editing ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val-input-wrap", children: [
1655
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-body", children: [
1656
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1657
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-fc-label", children: t("You") }),
1658
+ editing ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-edit", children: [
1629
1659
  /* @__PURE__ */ jsx(
1630
1660
  "input",
1631
1661
  {
1632
1662
  type: "number",
1633
- className: "ps-tryon-sr-fit-input",
1663
+ className: "ps-tryon-sr-fc-input",
1634
1664
  value: editVals[row.area] !== void 0 ? editVals[row.area] : row.userNum,
1635
1665
  onChange: (e) => setEditVals((prev) => ({ ...prev, [row.area]: e.target.value }))
1636
1666
  }
1637
1667
  ),
1638
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-unit", children: unitLbl })
1639
- ] }) : /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-fit-val-text", children: [
1668
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fc-unit", children: unitLbl })
1669
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-value", children: [
1640
1670
  row.userNum,
1641
1671
  " ",
1642
1672
  unitLbl
1643
1673
  ] })
1644
1674
  ] }),
1645
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-val", children: [
1646
- /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-fit-val-label", children: [
1675
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-col", children: [
1676
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-label", children: [
1647
1677
  t("Chart"),
1648
1678
  " (",
1649
1679
  selSize,
1650
1680
  ")"
1651
1681
  ] }),
1652
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-val-text", children: row.chartLabel })
1682
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fc-value", children: [
1683
+ row.chartLabel,
1684
+ " ",
1685
+ unitLbl
1686
+ ] })
1653
1687
  ] })
1654
1688
  ] })
1655
- ] }, i))
1689
+ ] }, i)) })
1656
1690
  ] }),
1657
1691
  fitRows.length === 0 && sizingResult.reasoning && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-reasoning", children: /* @__PURE__ */ jsx("p", { children: sizingResult.reasoning }) }),
1658
1692
  /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-ctas", children: [
@@ -2324,62 +2358,64 @@ const STYLES = `
2324
2358
  .ps-tryon-btn-retry:hover { background: rgba(255,255,255,0.12); }
2325
2359
 
2326
2360
  /* ── Size Result (redesigned) ── */
2327
- .ps-tryon-sr { display: flex; flex-direction: column; gap: 1.1vw; }
2328
- .ps-tryon-sr-loading { text-align: center; padding: 2vw 0; }
2329
- .ps-tryon-sr-loading p { font-size: 0.83vw; color: #999; margin-top: 0.5vw; }
2361
+ .ps-tryon-sr { display: flex; flex-direction: column; gap: 1.25vw; }
2362
+ .ps-tryon-sr-loading { text-align: center; padding: 3vw 0; }
2363
+ .ps-tryon-sr-loading p { font-size: 0.83vw; color: #666; margin-top: 0.6vw; }
2330
2364
  .ps-tryon-size-loading-spinner {
2331
- width: 2vw; height: 2vw; border: 3px solid #333;
2365
+ width: 1.8vw; height: 1.8vw; border: 2px solid #282828;
2332
2366
  border-top-color: #bb945c; border-radius: 50%;
2333
- animation: ps-spin 0.8s linear infinite; margin: 0 auto;
2367
+ animation: ps-spin 0.7s linear infinite; margin: 0 auto;
2334
2368
  }
2335
2369
  @keyframes ps-spin { to { transform: rotate(360deg); } }
2336
2370
 
2337
2371
  /* Hero */
2338
2372
  .ps-tryon-sr-hero {
2339
- display: flex; align-items: center; gap: 1vw; padding: 1vw 1.2vw;
2340
- background: linear-gradient(135deg, rgba(187,148,92,0.08), rgba(187,148,92,0.02));
2341
- border: 1.5px solid rgba(187,148,92,0.25); border-radius: 0.83vw;
2373
+ display: flex; align-items: center; gap: 1vw; padding: 1.1vw 1.3vw;
2374
+ background: linear-gradient(135deg, rgba(187,148,92,0.06), rgba(187,148,92,0.01));
2375
+ border: 1px solid rgba(187,148,92,0.2); border-radius: 0.83vw;
2342
2376
  }
2343
2377
  .ps-tryon-sr-hero-badge {
2344
- min-width: 3.5vw; height: 3.5vw; display: flex; align-items: center; justify-content: center;
2378
+ min-width: 3.2vw; height: 3.2vw; display: flex; align-items: center; justify-content: center;
2345
2379
  background: linear-gradient(135deg, #bb945c, #d6ba7d); color: #111;
2346
- font-size: 1.5vw; font-weight: 800; border-radius: 0.73vw; letter-spacing: -0.02em;
2347
- padding: 0 0.8vw; box-shadow: 0 0.4vw 1.2vw rgba(187,148,92,0.25);
2380
+ font-size: 1.35vw; font-weight: 800; border-radius: 0.63vw; letter-spacing: -0.02em;
2381
+ padding: 0 0.73vw; box-shadow: 0 0.3vw 1vw rgba(187,148,92,0.3);
2348
2382
  }
2349
2383
  .ps-tryon-sr-hero-info { flex: 1; }
2350
- .ps-tryon-sr-hero-title { font-size: 1.04vw; font-weight: 700; color: #fff; margin-bottom: 0.15vw; }
2351
- .ps-tryon-sr-hero-conf { font-size: 0.78vw; font-weight: 600; }
2384
+ .ps-tryon-sr-hero-title { font-size: 1vw; font-weight: 700; color: #fff; margin-bottom: 0.1vw; }
2385
+ .ps-tryon-sr-hero-conf { font-size: 0.73vw; font-weight: 600; }
2352
2386
  .ps-conf-high { color: #4ade80; } .ps-conf-medium { color: #bb945c; } .ps-conf-low { color: #ef4444; }
2353
2387
 
2388
+ /* Suggestion banner */
2389
+ .ps-tryon-sr-suggestion {
2390
+ display: flex; align-items: center; gap: 0.52vw;
2391
+ padding: 0.62vw 0.83vw; border-radius: 0.52vw;
2392
+ background: linear-gradient(135deg, rgba(187,148,92,0.1), rgba(187,148,92,0.04));
2393
+ border: 1px solid rgba(187,148,92,0.25);
2394
+ font-size: 0.73vw; color: #d6ba7d; cursor: pointer;
2395
+ animation: ps-fade-up 0.3s ease both; transition: background 0.2s;
2396
+ }
2397
+ .ps-tryon-sr-suggestion:hover { background: rgba(187,148,92,0.14); }
2398
+ .ps-tryon-sr-suggestion svg { stroke: #bb945c; flex-shrink: 0; }
2399
+ .ps-tryon-sr-suggestion strong { color: #fff; }
2400
+ .ps-tryon-sr-hero-badge-icon { background: linear-gradient(135deg, #333, #444); }
2401
+ .ps-tryon-sr-hero-badge-icon svg { stroke: #bb945c; }
2402
+
2403
+ /* Section titles */
2404
+ .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; }
2405
+
2354
2406
  /* International sizes */
2355
2407
  .ps-tryon-sr-intl { }
2356
- .ps-tryon-sr-label { font-size: 0.78vw; font-weight: 700; color: #999; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 0.52vw; }
2357
- .ps-tryon-sr-label-hint { font-weight: 400; text-transform: none; letter-spacing: 0; color: #666; font-style: italic; }
2358
- .ps-tryon-sr-intl-primary { display: flex; flex-wrap: wrap; gap: 0.42vw; margin-bottom: 0.52vw; }
2408
+ .ps-tryon-sr-intl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(3.8vw, 1fr)); gap: 0.42vw; }
2359
2409
  .ps-tryon-sr-intl-card {
2360
- flex: 1; min-width: 3.5vw; display: flex; flex-direction: column; align-items: center;
2361
- padding: 0.57vw 0.42vw; border: 1.5px solid #333; border-radius: 0.63vw;
2362
- background: #1a1b1a; transition: border-color 0.2s;
2410
+ display: flex; flex-direction: column; align-items: center;
2411
+ padding: 0.62vw 0.36vw; border: 1px solid #282828; border-radius: 0.52vw;
2412
+ background: #161616; transition: all 0.2s;
2363
2413
  }
2364
- .ps-tryon-sr-intl-card:hover { border-color: #555; }
2365
- .ps-tryon-sr-intl-card-val { font-size: 1.04vw; font-weight: 800; color: #fff; line-height: 1.2; }
2366
- .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; }
2367
-
2368
- .ps-tryon-sr-intl-more { }
2369
- .ps-tryon-sr-intl-more-btn {
2370
- font-size: 0.73vw; color: #bb945c; font-weight: 600; cursor: pointer;
2371
- list-style: none; margin-bottom: 0.42vw; font-family: inherit;
2372
- }
2373
- .ps-tryon-sr-intl-more-btn::-webkit-details-marker { display: none; }
2374
- .ps-tryon-sr-intl-more-btn::before { content: "▸ "; }
2375
- .ps-tryon-sr-intl-more[open] .ps-tryon-sr-intl-more-btn::before { content: "▾ "; }
2414
+ .ps-tryon-sr-intl-card:hover { border-color: #444; background: #1c1c1c; }
2415
+ .ps-tryon-sr-intl-card-val { font-size: 1.1vw; font-weight: 800; color: #fff; line-height: 1.15; }
2416
+ .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; }
2376
2417
 
2377
- .ps-tryon-sr-intl-grid { display: flex; flex-wrap: wrap; gap: 0.42vw; }
2378
- .ps-tryon-sr-intl-item {
2379
- display: flex; align-items: center; border: 1.5px solid #333; border-radius: 0.52vw; overflow: hidden;
2380
- }
2381
- .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; }
2382
- .ps-tryon-sr-intl-val { padding: 0.42vw 0.68vw; font-size: 0.83vw; color: #fff; font-weight: 700; }
2418
+ /* (intl grid uses .ps-tryon-sr-intl-grid defined above) */
2383
2419
 
2384
2420
  /* Size selector */
2385
2421
  .ps-tryon-sr-sizes { }
@@ -2405,55 +2441,61 @@ const STYLES = `
2405
2441
  .ps-tryon-sr-comparing { font-size: 0.73vw; color: #bb945c; margin-top: 0.42vw; }
2406
2442
  .ps-tryon-sr-comparing strong { color: #d6ba7d; }
2407
2443
 
2408
- /* Fit analysis cards */
2409
- .ps-tryon-sr-fit { display: flex; flex-direction: column; gap: 0.52vw; }
2410
- .ps-tryon-sr-fit-header-row {
2411
- display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.1vw;
2444
+ /* Fit analysis */
2445
+ .ps-tryon-sr-fit { }
2446
+ .ps-tryon-sr-fit-top {
2447
+ display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.52vw;
2412
2448
  }
2413
2449
  .ps-tryon-sr-edit-btn {
2414
2450
  display: inline-flex; align-items: center; gap: 0.31vw;
2415
- padding: 0.26vw 0.63vw; border: 1.5px solid #bb945c; border-radius: 0.36vw;
2416
- background: transparent; color: #bb945c; font-size: 0.63vw; font-weight: 600;
2451
+ padding: 0.31vw 0.73vw; border: 1px solid rgba(187,148,92,0.4); border-radius: 0.42vw;
2452
+ background: rgba(187,148,92,0.06); color: #bb945c; font-size: 0.68vw; font-weight: 600;
2417
2453
  cursor: pointer; font-family: inherit; transition: all 0.2s;
2418
2454
  }
2419
- .ps-tryon-sr-edit-btn:hover { background: rgba(187,148,92,0.1); }
2455
+ .ps-tryon-sr-edit-btn:hover { background: rgba(187,148,92,0.12); border-color: #bb945c; }
2420
2456
  .ps-tryon-sr-edit-btn svg { stroke: currentColor; }
2421
- .ps-tryon-sr-fit-card {
2422
- border: 1.5px solid #333; border-radius: 0.63vw; overflow: hidden; transition: border-color 0.2s;
2457
+
2458
+ .ps-tryon-sr-fit-cards { display: flex; flex-direction: column; gap: 0.42vw; }
2459
+
2460
+ .ps-tryon-sr-fc {
2461
+ border: 1px solid #282828; border-radius: 0.63vw; overflow: hidden;
2462
+ transition: border-color 0.2s;
2423
2463
  }
2424
- .ps-tryon-sr-fit-card.ps-fit-good { border-left: 3px solid #4ade80; }
2425
- .ps-tryon-sr-fit-card.ps-fit-tight { border-left: 3px solid #f59e0b; }
2426
- .ps-tryon-sr-fit-card.ps-fit-loose { border-left: 3px solid #60a5fa; }
2427
- .ps-tryon-sr-fit-card-top {
2464
+ .ps-tryon-sr-fc.ps-fit-good { border-left: 3px solid #4ade80; }
2465
+ .ps-tryon-sr-fc.ps-fit-tight { border-left: 3px solid #f59e0b; }
2466
+ .ps-tryon-sr-fc.ps-fit-loose { border-left: 3px solid #60a5fa; }
2467
+
2468
+ .ps-tryon-sr-fc-head {
2428
2469
  display: flex; align-items: center; justify-content: space-between;
2429
- padding: 0.52vw 0.83vw; background: #1a1b1a;
2430
- }
2431
- .ps-tryon-sr-fit-area { font-size: 0.83vw; font-weight: 600; color: #fff; }
2432
- .ps-tryon-sr-fit-card-bottom {
2433
- display: flex; gap: 1vw; padding: 0.52vw 0.83vw;
2470
+ padding: 0.57vw 0.83vw; background: #161616;
2434
2471
  }
2435
- .ps-tryon-sr-fit-val { flex: 1; }
2436
- .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; }
2437
- .ps-tryon-sr-fit-val-input-wrap { display: flex; align-items: center; gap: 0.26vw; }
2438
- .ps-tryon-sr-fit-val-text { font-size: 0.83vw; font-weight: 600; color: #ccc; }
2472
+ .ps-tryon-sr-fc-area { font-size: 0.83vw; font-weight: 700; color: #fff; }
2439
2473
 
2440
- .ps-tryon-sr-fit-input {
2441
- width: 4vw; padding: 0.31vw 0.42vw; border: 1.5px solid #444; border-radius: 0.36vw;
2442
- background: #0c0c0d; color: #fff; font-size: 0.83vw; font-weight: 600; font-family: inherit;
2443
- outline: none; text-align: center; -moz-appearance: textfield;
2474
+ .ps-tryon-sr-fc-badge {
2475
+ display: inline-flex; align-items: center; gap: 0.21vw; padding: 0.21vw 0.52vw;
2476
+ border-radius: 0.31vw; font-size: 0.63vw; font-weight: 700; white-space: nowrap;
2444
2477
  }
2445
- .ps-tryon-sr-fit-input::-webkit-outer-spin-button,
2446
- .ps-tryon-sr-fit-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2447
- .ps-tryon-sr-fit-input:focus { border-color: #bb945c; background: #1a1b1a; }
2448
- .ps-tryon-sr-fit-unit { font-size: 0.68vw; color: #666; }
2478
+ .ps-tryon-sr-fc-badge.ps-fit-good { background: rgba(74,222,128,0.08); color: #4ade80; }
2479
+ .ps-tryon-sr-fc-badge.ps-fit-tight { background: rgba(245,158,11,0.08); color: #f59e0b; }
2480
+ .ps-tryon-sr-fc-badge.ps-fit-loose { background: rgba(96,165,250,0.08); color: #60a5fa; }
2449
2481
 
2450
- .ps-tryon-sr-fit-badge {
2451
- display: inline-flex; align-items: center; gap: 0.26vw; padding: 0.26vw 0.57vw;
2452
- border-radius: 0.36vw; font-size: 0.68vw; font-weight: 700; white-space: nowrap;
2482
+ .ps-tryon-sr-fc-body {
2483
+ display: flex; gap: 1.5vw; padding: 0.52vw 0.83vw 0.62vw;
2484
+ }
2485
+ .ps-tryon-sr-fc-col { flex: 1; }
2486
+ .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; }
2487
+ .ps-tryon-sr-fc-value { font-size: 0.88vw; font-weight: 600; color: #ccc; }
2488
+ .ps-tryon-sr-fc-edit { display: flex; align-items: center; gap: 0.26vw; }
2489
+ .ps-tryon-sr-fc-input {
2490
+ width: 4.2vw; padding: 0.26vw 0.42vw; border: 1.5px solid #444; border-radius: 0.36vw;
2491
+ background: #0c0c0d; color: #fff; font-size: 0.88vw; font-weight: 600; font-family: inherit;
2492
+ outline: none; text-align: center; -moz-appearance: textfield;
2493
+ transition: border-color 0.2s, background 0.2s;
2453
2494
  }
2454
- .ps-tryon-sr-fit-badge.ps-fit-good { background: rgba(74,222,128,0.1); color: #4ade80; }
2455
- .ps-tryon-sr-fit-badge.ps-fit-tight { background: rgba(245,158,11,0.1); color: #f59e0b; }
2456
- .ps-tryon-sr-fit-badge.ps-fit-loose { background: rgba(96,165,250,0.1); color: #60a5fa; }
2495
+ .ps-tryon-sr-fc-input::-webkit-outer-spin-button,
2496
+ .ps-tryon-sr-fc-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2497
+ .ps-tryon-sr-fc-input:focus { border-color: #bb945c; background: #1a1a1a; }
2498
+ .ps-tryon-sr-fc-unit { font-size: 0.63vw; color: #555; }
2457
2499
 
2458
2500
  /* Compare dropdown */
2459
2501
  .ps-tryon-sr-compare { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "3.20.0",
3
+ "version": "4.1.0",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",