@primestyleai/tryon 3.14.0 → 3.15.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.
@@ -302,6 +302,10 @@ const en = {
302
302
  "Equivalent Sizes": "Equivalent Sizes",
303
303
  "Analyzing your size...": "Analyzing your size...",
304
304
  "Your size:": "Your size:",
305
+ "Size Chart": "Size Chart",
306
+ "tap to compare": "tap to compare",
307
+ "Comparing size": "Comparing size",
308
+ "Fit Analysis": "Fit Analysis",
305
309
  "Done": "Done",
306
310
  // ── Try-on result ───────────────────────────────────
307
311
  "Try-on result": "Try-on result",
@@ -1,5 +1,5 @@
1
- import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-25Bm_pob.js";
2
- import { P, b, T, d, r } from "./index-25Bm_pob.js";
1
+ import { c as createT, A as ApiClient, S as SseClient, i as isValidImageFile, a as compressImage } from "./index-B8Dg-nJ7.js";
2
+ import { P, b, T, d, r } from "./index-B8Dg-nJ7.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-25Bm_pob.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-B8Dg-nJ7.js";
5
5
  const HEADER_ALIASES = {
6
6
  // ── Size label columns (skipped during field derivation) ──
7
7
  size: "__size__",
@@ -438,6 +438,9 @@ function detectLocale() {
438
438
  function isImperial(locale) {
439
439
  return locale === "US" || locale === "UK";
440
440
  }
441
+ function cmToIn(cm) {
442
+ return +(cm / 2.54).toFixed(1);
443
+ }
441
444
  function inToCm(inches) {
442
445
  return +(inches * 2.54).toFixed(1);
443
446
  }
@@ -1489,63 +1492,191 @@ function PrimeStyleTryonInner({
1489
1492
  ] }, `form-${formGender}-${sizingUnit}-${heightUnit}-${sizingCountry}-${formKey}`);
1490
1493
  }
1491
1494
  function SizeResultView() {
1492
- const [showFitDetails, setShowFitDetails] = useState(false);
1493
- const confidenceLabel = sizingResult?.confidence === "high" ? t("High Confidence") : sizingResult?.confidence === "medium" ? t("Medium Confidence") : sizingResult?.confidence === "low" ? t("Low Confidence") : "";
1494
- return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-result-view", children: [
1495
- sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend ps-tryon-sizing-loading", children: [
1495
+ const [activeSize, setActiveSize] = useState(sizingResult?.recommendedSize || "");
1496
+ const [editedValues, setEditedValues] = useState({});
1497
+ const isCmResult = sizingUnit === "cm";
1498
+ const chartData = useMemo(() => {
1499
+ if (!sizeGuide?.found || !sizeGuide.headers || !sizeGuide.rows) return null;
1500
+ const INTL = /* @__PURE__ */ new Set(["eu", "us", "uk", "it", "fr", "de", "jp", "cn", "kr", "au", "br", "eur"]);
1501
+ const MEAS_MAP = {
1502
+ chest: "chest",
1503
+ bust: "bust",
1504
+ waist: "waist",
1505
+ hips: "hips",
1506
+ hip: "hips",
1507
+ shoulder: "shoulderWidth",
1508
+ shoulders: "shoulderWidth",
1509
+ "shoulder width": "shoulderWidth",
1510
+ sleeve: "sleeveLength",
1511
+ "sleeve length": "sleeveLength",
1512
+ inseam: "inseam",
1513
+ neck: "neckCircumference",
1514
+ "neck circumference": "neckCircumference",
1515
+ foot: "footLengthCm",
1516
+ "foot length": "footLengthCm"
1517
+ };
1518
+ const sizeColIdx = sizeGuide.headers.findIndex((h) => /^size$/i.test(h.trim()));
1519
+ const idx = sizeColIdx >= 0 ? sizeColIdx : 0;
1520
+ const measCols = [];
1521
+ const intlCols = [];
1522
+ sizeGuide.headers.forEach((h, i) => {
1523
+ if (i === idx) return;
1524
+ const lower = h.toLowerCase().trim().replace(/\s*\(.*\)/, "");
1525
+ const clean = lower.replace(/\s*size\s*/gi, "").trim();
1526
+ if (INTL.has(clean)) {
1527
+ intlCols.push({ headerIdx: i, code: clean.toUpperCase() });
1528
+ } else if (MEAS_MAP[clean]) {
1529
+ measCols.push({ headerIdx: i, label: h.trim(), formKey: MEAS_MAP[clean] });
1530
+ } else if (lower !== "size") {
1531
+ measCols.push({ headerIdx: i, label: h.trim(), formKey: lower.replace(/\s+/g, "") });
1532
+ }
1533
+ });
1534
+ const sizes = sizeGuide.rows.map((row) => {
1535
+ const label = row[idx] || "";
1536
+ const measurements = {};
1537
+ for (const col of measCols) {
1538
+ const cell = row[col.headerIdx] || "";
1539
+ const nums = cell.replace(/[^\d.\-–]/g, " ").trim().split(/[\s\-–]+/).filter(Boolean).map(Number).filter((n) => !isNaN(n));
1540
+ if (nums.length > 0) {
1541
+ measurements[col.formKey] = { raw: cell, min: Math.min(...nums), max: Math.max(...nums) };
1542
+ }
1543
+ }
1544
+ const intl = {};
1545
+ for (const col of intlCols) {
1546
+ if (row[col.headerIdx]) intl[col.code] = row[col.headerIdx];
1547
+ }
1548
+ return { label, measurements, intl };
1549
+ });
1550
+ return { sizes, measCols, intlCols };
1551
+ }, [sizeGuide]);
1552
+ const getUserVal = useCallback((formKey2) => {
1553
+ const edited = editedValues[formKey2];
1554
+ if (edited !== void 0 && edited !== "") {
1555
+ const v2 = parseFloat(edited);
1556
+ return isNaN(v2) ? null : isCmResult ? v2 : inToCm(v2);
1557
+ }
1558
+ const raw = formRef.current[formKey2];
1559
+ if (!raw) return null;
1560
+ const v = parseFloat(raw);
1561
+ return isNaN(v) ? null : isCmResult ? v : inToCm(v);
1562
+ }, [editedValues, isCmResult]);
1563
+ const activeFit = useMemo(() => {
1564
+ if (!chartData) return null;
1565
+ const sizeRow = chartData.sizes.find((s) => s.label === activeSize);
1566
+ if (!sizeRow) return null;
1567
+ const details = [];
1568
+ for (const col of chartData.measCols) {
1569
+ const range = sizeRow.measurements[col.formKey];
1570
+ if (!range) continue;
1571
+ const userVal = getUserVal(col.formKey);
1572
+ if (userVal === null) continue;
1573
+ const fit = userVal >= range.min && userVal <= range.max ? "good" : userVal < range.min ? "tight" : "loose";
1574
+ details.push({ label: col.label, formKey: col.formKey, userVal, chartMin: range.min, chartMax: range.max, chartRaw: range.raw, fit });
1575
+ }
1576
+ return details;
1577
+ }, [chartData, activeSize, getUserVal]);
1578
+ const activeIntl = useMemo(() => {
1579
+ if (!chartData) return sizingResult?.internationalSizes || {};
1580
+ const sizeRow = chartData.sizes.find((s) => s.label === activeSize);
1581
+ return sizeRow?.intl || sizingResult?.internationalSizes || {};
1582
+ }, [chartData, activeSize, sizingResult]);
1583
+ const fmtRange = (min, max) => {
1584
+ if (isCmResult) return min === max ? `${Math.round(min)}` : `${Math.round(min)}–${Math.round(max)}`;
1585
+ return min === max ? `${cmToIn(min)}` : `${cmToIn(min)}–${cmToIn(max)}`;
1586
+ };
1587
+ const unitLabel = isCmResult ? t("cm") : t("in");
1588
+ const isRecommended = activeSize === sizingResult?.recommendedSize;
1589
+ return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr", children: [
1590
+ sizingLoading && !sizingResult && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-loading", children: [
1496
1591
  /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner" }),
1497
- /* @__PURE__ */ jsx("p", { className: "ps-tryon-size-reasoning", children: t("Analyzing your size...") })
1592
+ /* @__PURE__ */ jsx("p", { children: t("Analyzing your size...") })
1498
1593
  ] }),
1499
1594
  sizingResult && /* @__PURE__ */ jsxs(Fragment, { children: [
1500
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-recommend", children: [
1501
- /* @__PURE__ */ jsx("h3", { className: "ps-tryon-size-title", children: t("Your Size") }),
1502
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-size-hero-row", children: [
1503
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-badge", children: sizingResult.recommendedSize }),
1504
- /* @__PURE__ */ jsx("span", { className: `ps-tryon-size-conf-label ps-conf-${sizingResult.confidence}`, children: confidenceLabel })
1505
- ] }),
1506
- sizingResult.sections && Object.keys(sizingResult.sections).length > 1 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-multi-section", children: [
1507
- /* @__PURE__ */ jsx("h4", { className: "ps-tryon-fit-summary-title", children: t("Sizing by Garment") }),
1508
- Object.entries(sizingResult.sections).map(([name, sec]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-section-row", children: [
1509
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-section-name", children: name }),
1510
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-size-badge ps-tryon-section-badge", children: sec.recommendedSize })
1511
- ] }, name))
1512
- ] }),
1513
- sizingResult.matchDetails && sizingResult.matchDetails.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-fit-summary", children: [
1514
- /* @__PURE__ */ jsx("h4", { className: "ps-tryon-fit-summary-title", children: t("Fit Summary") }),
1515
- sizingResult.matchDetails.map((m, i) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-fit-row", children: [
1516
- /* @__PURE__ */ jsx("span", { className: `ps-tryon-fit-icon ps-fit-icon-${m.fit}`, children: m.fit === "good" ? "✓" : m.fit === "tight" ? "↑" : "↓" }),
1517
- /* @__PURE__ */ jsxs("span", { className: "ps-tryon-fit-text", children: [
1518
- /* @__PURE__ */ jsx("strong", { children: m.measurement }),
1519
- " ",
1520
- m.fit === "good" ? t("within range") : m.fit === "tight" ? t("may be snug") : t("may be loose")
1521
- ] })
1522
- ] }, i)),
1523
- /* @__PURE__ */ jsx("button", { className: "ps-tryon-fit-details-toggle", onClick: () => setShowFitDetails(!showFitDetails), children: showFitDetails ? `${t("Hide details")} ↑` : `${t("See details")} ↓` }),
1524
- showFitDetails && /* @__PURE__ */ jsxs("table", { className: "ps-tryon-fit-table", children: [
1525
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
1526
- /* @__PURE__ */ jsx("th", { children: t("Area") }),
1527
- /* @__PURE__ */ jsx("th", { children: t("You") }),
1528
- /* @__PURE__ */ jsx("th", { children: t("Chart") }),
1529
- /* @__PURE__ */ jsx("th", { children: t("Fit") })
1530
- ] }) }),
1531
- /* @__PURE__ */ jsx("tbody", { children: sizingResult.matchDetails.map((m, i) => /* @__PURE__ */ jsxs("tr", { children: [
1532
- /* @__PURE__ */ jsx("td", { children: m.measurement }),
1533
- /* @__PURE__ */ jsx("td", { children: m.userValue }),
1534
- /* @__PURE__ */ jsx("td", { children: m.chartRange }),
1535
- /* @__PURE__ */ jsx("td", { className: `ps-fit-${m.fit}`, children: m.fit })
1536
- ] }, i)) })
1595
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero", children: [
1596
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-badge", children: sizingResult.recommendedSize }),
1597
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-hero-info", children: [
1598
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-hero-title", children: t("Your Size") }),
1599
+ /* @__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") })
1600
+ ] })
1601
+ ] }),
1602
+ Object.keys(activeIntl).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl", children: [
1603
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Equivalent Sizes") }),
1604
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-intl-grid", children: Object.entries(activeIntl).map(([code, val]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-intl-item", children: [
1605
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-code", children: code }),
1606
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-intl-val", children: val })
1607
+ ] }, code)) })
1608
+ ] }),
1609
+ chartData && chartData.sizes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-sizes", children: [
1610
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-label", children: [
1611
+ t("Size Chart"),
1612
+ " ",
1613
+ /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-label-hint", children: [
1614
+ " ",
1615
+ t("tap to compare")
1537
1616
  ] })
1538
1617
  ] }),
1539
- sizingResult.internationalSizes && Object.keys(sizingResult.internationalSizes).length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-equiv-section", children: [
1540
- /* @__PURE__ */ jsx("h4", { className: "ps-tryon-equiv-title", children: t("Equivalent Sizes") }),
1541
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-equiv-chips", children: Object.entries(sizingResult.internationalSizes).map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "ps-tryon-equiv-chip", children: [
1542
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-equiv-region", children: k }),
1543
- /* @__PURE__ */ jsx("span", { className: "ps-tryon-equiv-value", children: v })
1544
- ] }, k)) })
1545
- ] }),
1546
- (!sizingResult.matchDetails || sizingResult.matchDetails.length === 0) && sizingResult.reasoning && /* @__PURE__ */ jsx("p", { className: "ps-tryon-size-reasoning", children: sizingResult.reasoning })
1618
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-size-row", children: chartData.sizes.map((s) => /* @__PURE__ */ jsxs(
1619
+ "button",
1620
+ {
1621
+ onClick: () => setActiveSize(s.label),
1622
+ className: `ps-tryon-sr-size-chip${s.label === activeSize ? " ps-active" : ""}${s.label === sizingResult.recommendedSize ? " ps-recommended" : ""}`,
1623
+ children: [
1624
+ s.label,
1625
+ s.label === sizingResult.recommendedSize && /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-rec-dot" })
1626
+ ]
1627
+ },
1628
+ s.label
1629
+ )) }),
1630
+ !isRecommended && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-comparing", children: [
1631
+ t("Comparing size"),
1632
+ " ",
1633
+ /* @__PURE__ */ jsx("strong", { children: activeSize })
1634
+ ] })
1635
+ ] }),
1636
+ activeFit && activeFit.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit", children: [
1637
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-label", children: t("Fit Analysis") }),
1638
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-table", children: [
1639
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-fit-header", children: [
1640
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-area", children: t("Area") }),
1641
+ /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-fit-col-you", children: [
1642
+ t("You"),
1643
+ " (",
1644
+ unitLabel,
1645
+ ")"
1646
+ ] }),
1647
+ /* @__PURE__ */ jsxs("span", { className: "ps-tryon-sr-fit-col-chart", children: [
1648
+ t("Chart"),
1649
+ " (",
1650
+ unitLabel,
1651
+ ")"
1652
+ ] }),
1653
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-fit", children: t("Fit") })
1654
+ ] }),
1655
+ activeFit.map((row, i) => /* @__PURE__ */ jsxs("div", { className: `ps-tryon-sr-fit-row ps-fit-${row.fit}`, children: [
1656
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-area", children: row.label }),
1657
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-you", children: /* @__PURE__ */ jsx(
1658
+ "input",
1659
+ {
1660
+ type: "number",
1661
+ className: "ps-tryon-sr-fit-input",
1662
+ defaultValue: isCmResult ? Math.round(row.userVal) : cmToIn(row.userVal),
1663
+ onBlur: (e) => {
1664
+ const val = e.target.value;
1665
+ setEditedValues((prev) => ({ ...prev, [row.formKey]: val }));
1666
+ }
1667
+ }
1668
+ ) }),
1669
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-chart", children: fmtRange(row.chartMin, row.chartMax) }),
1670
+ /* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-fit-col-fit", children: /* @__PURE__ */ jsxs("span", { className: `ps-tryon-sr-fit-badge ps-fit-${row.fit}`, children: [
1671
+ row.fit === "good" ? "✓" : row.fit === "tight" ? "↑" : "↓",
1672
+ " ",
1673
+ row.fit === "good" ? t("within range") : row.fit === "tight" ? t("may be snug") : t("may be loose")
1674
+ ] }) })
1675
+ ] }, i))
1676
+ ] })
1547
1677
  ] }),
1548
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-tryon-cta", children: [
1678
+ (!activeFit || activeFit.length === 0) && sizingResult.reasoning && /* @__PURE__ */ jsx("div", { className: "ps-tryon-sr-reasoning", children: /* @__PURE__ */ jsx("p", { children: sizingResult.reasoning }) }),
1679
+ /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-ctas", children: [
1549
1680
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-cta", onClick: () => setView("upload"), children: [
1550
1681
  t("See how it looks on you"),
1551
1682
  " ",
@@ -2213,79 +2344,120 @@ const STYLES = `
2213
2344
  .ps-tryon-btn-retry { background: rgba(255,255,255,0.08); color: #fff; border: 1px solid #333 !important; }
2214
2345
  .ps-tryon-btn-retry:hover { background: rgba(255,255,255,0.12); }
2215
2346
 
2216
- /* Size recommendation */
2217
- .ps-tryon-size-recommend { margin-bottom: 0.83vw; }
2218
- .ps-tryon-size-title { font-size: 0.94vw; font-weight: 700; color: #fff; margin: 0 0 0.73vw; }
2219
- .ps-tryon-size-hero-row {
2220
- display: flex; align-items: center; gap: 0.83vw; padding: 0.83vw 1.04vw;
2221
- border: 1.5px solid #333; border-radius: 0.73vw; margin-bottom: 0.94vw; background: rgba(255,255,255,0.02);
2222
- }
2223
- .ps-tryon-size-badge {
2224
- display: inline-flex; align-items: center; justify-content: center;
2225
- min-width: 2.92vw; height: 2.92vw; padding: 0 0.63vw; border-radius: 0.63vw;
2226
- background: linear-gradient(135deg, #bb945c, #d6ba7d);
2227
- color: #111; font-size: 1.25vw; font-weight: 800; letter-spacing: -0.02em;
2228
- }
2229
- .ps-tryon-size-conf-label { font-size: 0.78vw; font-weight: 600; }
2230
- .ps-conf-high { color: #4ade80; } .ps-conf-medium { color: #bb945c; } .ps-conf-low { color: #ef4444; }
2231
-
2232
- .ps-tryon-sizing-loading { text-align: center; padding: 1.04vw 0; }
2347
+ /* ── Size Result (redesigned) ── */
2348
+ .ps-tryon-sr { display: flex; flex-direction: column; gap: 1.1vw; }
2349
+ .ps-tryon-sr-loading { text-align: center; padding: 2vw 0; }
2350
+ .ps-tryon-sr-loading p { font-size: 0.83vw; color: #999; margin-top: 0.5vw; }
2233
2351
  .ps-tryon-size-loading-spinner {
2234
- width: 1.88vw; height: 1.88vw; border: 3px solid #333;
2352
+ width: 2vw; height: 2vw; border: 3px solid #333;
2235
2353
  border-top-color: #bb945c; border-radius: 50%;
2236
- animation: ps-spin 0.8s linear infinite; margin: 0 auto 0.63vw;
2354
+ animation: ps-spin 0.8s linear infinite; margin: 0 auto;
2237
2355
  }
2238
2356
  @keyframes ps-spin { to { transform: rotate(360deg); } }
2239
2357
 
2240
- /* Fit Summary */
2241
- .ps-tryon-fit-summary { margin-bottom: 0.83vw; }
2242
- .ps-tryon-fit-summary-title { font-size: 0.78vw; font-weight: 700; color: #fff; margin: 0 0 0.52vw; }
2243
- .ps-tryon-fit-row { display: flex; align-items: center; gap: 0.52vw; padding: 0.42vw 0; }
2244
- .ps-tryon-fit-icon {
2245
- width: 1.15vw; height: 1.15vw; border-radius: 50%; display: flex; align-items: center; justify-content: center;
2246
- font-size: 0.63vw; font-weight: 700; flex-shrink: 0;
2247
- }
2248
- .ps-fit-icon-good { background: rgba(74,222,128,0.15); color: #4ade80; }
2249
- .ps-fit-icon-tight { background: rgba(245,158,11,0.15); color: #f59e0b; }
2250
- .ps-fit-icon-loose { background: rgba(96,165,250,0.15); color: #60a5fa; }
2251
- .ps-tryon-fit-text { font-size: 0.73vw; color: #ccc; line-height: 1.4; }
2252
- .ps-tryon-fit-text strong { color: #fff; font-weight: 600; }
2253
- .ps-tryon-fit-details-toggle {
2254
- display: inline-block; margin-top: 0.42vw; font-size: 0.68vw; color: #bb945c; cursor: pointer;
2255
- font-weight: 600; background: none; border: none; padding: 0; font-family: inherit;
2256
- }
2257
- .ps-tryon-fit-details-toggle:hover { color: #d6ba7d; }
2258
- .ps-tryon-fit-table { width: 100%; border-collapse: collapse; margin-top: 0.52vw; font-size: 0.68vw; }
2259
- .ps-tryon-fit-table th { text-align: left; padding: 0.42vw 0.52vw; border-bottom: 1px solid #333; color: #999; font-weight: 600; }
2260
- .ps-tryon-fit-table td { padding: 0.42vw 0.52vw; border-bottom: 1px solid #222; color: #ccc; }
2261
- .ps-fit-good { color: #4ade80; } .ps-fit-tight { color: #f59e0b; } .ps-fit-loose { color: #60a5fa; }
2358
+ /* Hero */
2359
+ .ps-tryon-sr-hero {
2360
+ display: flex; align-items: center; gap: 1vw; padding: 1vw 1.2vw;
2361
+ background: linear-gradient(135deg, rgba(187,148,92,0.08), rgba(187,148,92,0.02));
2362
+ border: 1.5px solid rgba(187,148,92,0.25); border-radius: 0.83vw;
2363
+ }
2364
+ .ps-tryon-sr-hero-badge {
2365
+ min-width: 3.5vw; height: 3.5vw; display: flex; align-items: center; justify-content: center;
2366
+ background: linear-gradient(135deg, #bb945c, #d6ba7d); color: #111;
2367
+ font-size: 1.5vw; font-weight: 800; border-radius: 0.73vw; letter-spacing: -0.02em;
2368
+ padding: 0 0.8vw; box-shadow: 0 0.4vw 1.2vw rgba(187,148,92,0.25);
2369
+ }
2370
+ .ps-tryon-sr-hero-info { flex: 1; }
2371
+ .ps-tryon-sr-hero-title { font-size: 1.04vw; font-weight: 700; color: #fff; margin-bottom: 0.15vw; }
2372
+ .ps-tryon-sr-hero-conf { font-size: 0.78vw; font-weight: 600; }
2373
+ .ps-conf-high { color: #4ade80; } .ps-conf-medium { color: #bb945c; } .ps-conf-low { color: #ef4444; }
2262
2374
 
2263
- /* Equivalent Sizes */
2264
- .ps-tryon-equiv-section { margin-bottom: 0.83vw; }
2265
- .ps-tryon-equiv-title { font-size: 0.78vw; font-weight: 700; color: #fff; margin: 0 0 0.52vw; }
2266
- .ps-tryon-equiv-chips { display: flex; flex-wrap: wrap; gap: 0.42vw; }
2267
- .ps-tryon-equiv-chip {
2375
+ /* International sizes */
2376
+ .ps-tryon-sr-intl { }
2377
+ .ps-tryon-sr-label { font-size: 0.78vw; font-weight: 700; color: #999; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 0.52vw; }
2378
+ .ps-tryon-sr-label-hint { font-weight: 400; text-transform: none; letter-spacing: 0; color: #666; font-style: italic; }
2379
+ .ps-tryon-sr-intl-grid { display: flex; flex-wrap: wrap; gap: 0.42vw; }
2380
+ .ps-tryon-sr-intl-item {
2268
2381
  display: flex; align-items: center; border: 1.5px solid #333; border-radius: 0.52vw; overflow: hidden;
2269
2382
  }
2270
- .ps-tryon-equiv-region { padding: 0.36vw 0.52vw; font-size: 0.63vw; color: #999; font-weight: 600; background: rgba(255,255,255,0.03); }
2271
- .ps-tryon-equiv-value { padding: 0.36vw 0.63vw; font-size: 0.73vw; color: #fff; font-weight: 700; }
2383
+ .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; }
2384
+ .ps-tryon-sr-intl-val { padding: 0.42vw 0.68vw; font-size: 0.83vw; color: #fff; font-weight: 700; }
2385
+
2386
+ /* Size selector */
2387
+ .ps-tryon-sr-sizes { }
2388
+ .ps-tryon-sr-size-row { display: flex; flex-wrap: wrap; gap: 0.36vw; }
2389
+ .ps-tryon-sr-size-chip {
2390
+ position: relative; min-width: 2.6vw; height: 2.4vw; padding: 0 0.73vw;
2391
+ display: flex; align-items: center; justify-content: center;
2392
+ border: 1.5px solid #333; border-radius: 0.52vw; background: transparent;
2393
+ color: #999; font-size: 0.83vw; font-weight: 600; cursor: pointer;
2394
+ transition: all 0.2s; font-family: inherit;
2395
+ }
2396
+ .ps-tryon-sr-size-chip:hover { border-color: #555; color: #ccc; }
2397
+ .ps-tryon-sr-size-chip.ps-active {
2398
+ border-color: #bb945c; background: #bb945c; color: #111;
2399
+ box-shadow: 0 0.2vw 0.8vw rgba(187,148,92,0.2);
2400
+ }
2401
+ .ps-tryon-sr-size-chip.ps-recommended { border-color: rgba(187,148,92,0.4); }
2402
+ .ps-tryon-sr-rec-dot {
2403
+ position: absolute; bottom: -0.26vw; left: 50%; transform: translateX(-50%);
2404
+ width: 0.31vw; height: 0.31vw; border-radius: 50%; background: #bb945c;
2405
+ }
2406
+ .ps-tryon-sr-size-chip.ps-active .ps-tryon-sr-rec-dot { background: #111; }
2407
+ .ps-tryon-sr-comparing { font-size: 0.73vw; color: #bb945c; margin-top: 0.42vw; }
2408
+ .ps-tryon-sr-comparing strong { color: #d6ba7d; }
2272
2409
 
2273
- /* Multi-section garment sizing (tuxedo/set) */
2274
- .ps-tryon-multi-section { margin-bottom: 0.83vw; }
2275
- .ps-tryon-section-row { display: flex; align-items: center; justify-content: space-between; padding: 0.52vw 0; border-bottom: 1px solid #222; }
2276
- .ps-tryon-section-row:last-child { border-bottom: none; }
2277
- .ps-tryon-section-name { font-size: 0.78vw; color: #ccc; font-weight: 500; }
2278
- .ps-tryon-section-badge { font-size: 0.83vw; min-width: auto; padding: 0.26vw 0.83vw; }
2410
+ /* Fit analysis table */
2411
+ .ps-tryon-sr-fit { }
2412
+ .ps-tryon-sr-fit-table { border: 1.5px solid #333; border-radius: 0.73vw; overflow: hidden; }
2413
+ .ps-tryon-sr-fit-header {
2414
+ display: flex; padding: 0.57vw 0.83vw; background: #1a1b1a; border-bottom: 1px solid #333;
2415
+ }
2416
+ .ps-tryon-sr-fit-header span {
2417
+ font-size: 0.68vw; font-weight: 700; color: #666; text-transform: uppercase; letter-spacing: 0.06em;
2418
+ }
2419
+ .ps-tryon-sr-fit-row {
2420
+ display: flex; align-items: center; padding: 0.57vw 0.83vw;
2421
+ border-bottom: 1px solid #222; transition: background 0.15s;
2422
+ }
2423
+ .ps-tryon-sr-fit-row:last-child { border-bottom: none; }
2424
+ .ps-tryon-sr-fit-row:hover { background: rgba(255,255,255,0.02); }
2425
+ .ps-tryon-sr-fit-row.ps-fit-good { border-left: 3px solid #4ade80; }
2426
+ .ps-tryon-sr-fit-row.ps-fit-tight { border-left: 3px solid #f59e0b; }
2427
+ .ps-tryon-sr-fit-row.ps-fit-loose { border-left: 3px solid #60a5fa; }
2279
2428
 
2280
- .ps-tryon-size-reasoning { font-size: 0.73vw; color: #ccc; line-height: 1.6; margin-bottom: 0.73vw; }
2429
+ .ps-tryon-sr-fit-col-area { flex: 0 0 28%; font-size: 0.78vw; font-weight: 600; color: #fff; }
2430
+ .ps-tryon-sr-fit-col-you { flex: 0 0 22%; }
2431
+ .ps-tryon-sr-fit-col-chart { flex: 0 0 22%; font-size: 0.78vw; color: #999; font-weight: 500; }
2432
+ .ps-tryon-sr-fit-col-fit { flex: 1; text-align: right; }
2281
2433
 
2282
- /* Size Result View (standalone sizing result before try-on) */
2283
- .ps-tryon-size-result-view { display: flex; flex-direction: column; gap: 1vw; }
2284
- .ps-tryon-tryon-cta { display: flex; flex-direction: column; gap: 0.7vw; margin-top: 0.7vw; }
2434
+ .ps-tryon-sr-fit-input {
2435
+ width: 3.5vw; padding: 0.26vw 0.42vw; border: 1.5px solid #333; border-radius: 0.36vw;
2436
+ background: #111211; color: #fff; font-size: 0.78vw; font-weight: 600; font-family: inherit;
2437
+ outline: none; text-align: center; -moz-appearance: textfield;
2438
+ }
2439
+ .ps-tryon-sr-fit-input::-webkit-outer-spin-button,
2440
+ .ps-tryon-sr-fit-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
2441
+ .ps-tryon-sr-fit-input:focus { border-color: #bb945c; }
2442
+
2443
+ .ps-tryon-sr-fit-badge {
2444
+ display: inline-flex; align-items: center; gap: 0.26vw; padding: 0.21vw 0.52vw;
2445
+ border-radius: 0.36vw; font-size: 0.63vw; font-weight: 700; white-space: nowrap;
2446
+ }
2447
+ .ps-tryon-sr-fit-badge.ps-fit-good { background: rgba(74,222,128,0.1); color: #4ade80; }
2448
+ .ps-tryon-sr-fit-badge.ps-fit-tight { background: rgba(245,158,11,0.1); color: #f59e0b; }
2449
+ .ps-tryon-sr-fit-badge.ps-fit-loose { background: rgba(96,165,250,0.1); color: #60a5fa; }
2450
+
2451
+ /* Reasoning fallback */
2452
+ .ps-tryon-sr-reasoning { padding: 0.83vw; border: 1px solid #333; border-radius: 0.63vw; background: #1a1b1a; }
2453
+ .ps-tryon-sr-reasoning p { font-size: 0.78vw; color: #ccc; line-height: 1.6; margin: 0; }
2454
+
2455
+ /* CTAs */
2456
+ .ps-tryon-sr-ctas { display: flex; flex-direction: column; gap: 0.52vw; margin-top: 0.36vw; }
2285
2457
  .ps-tryon-btn-secondary {
2286
2458
  background: transparent; border: 1.5px solid #444; color: #999; font-size: 0.83vw;
2287
- font-weight: 600; padding: 0.7vw 1.3vw; border-radius: 0.52vw;
2288
- cursor: pointer; transition: all 0.2s;
2459
+ font-weight: 600; padding: 0.73vw 1.3vw; border-radius: 0.52vw;
2460
+ cursor: pointer; transition: all 0.2s; font-family: inherit;
2289
2461
  }
2290
2462
  .ps-tryon-btn-secondary:hover { border-color: #666; color: #ccc; }
2291
2463
  .ps-tryon-size-compact { padding: 0.5vw 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primestyleai/tryon",
3
- "version": "3.14.0",
3
+ "version": "3.15.0",
4
4
  "description": "PrimeStyle Virtual Try-On SDK — React component & Web Component",
5
5
  "type": "module",
6
6
  "main": "dist/primestyle-tryon.js",