@primestyleai/tryon 5.8.39 → 5.8.41

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.
@@ -13092,6 +13092,101 @@ const STYLES$1 = `
13092
13092
  }
13093
13093
  .ps-pm-preview-remove:hover { background: #FFFFFF; }
13094
13094
 
13095
+ /* ── Mobile age-gate overlay ── */
13096
+ .ps-pm-preview-blurred {
13097
+ filter: blur(6px) saturate(0.7);
13098
+ pointer-events: none;
13099
+ user-select: none;
13100
+ }
13101
+ .ps-pm-age-gate {
13102
+ position: absolute; inset: 0;
13103
+ display: flex; align-items: center; justify-content: center;
13104
+ padding: max(16px, 4vw);
13105
+ background: rgba(255, 255, 255, 0.55);
13106
+ backdrop-filter: blur(8px);
13107
+ -webkit-backdrop-filter: blur(8px);
13108
+ z-index: 2;
13109
+ animation: ps-pm-age-gate-in 0.28s ease-out both;
13110
+ }
13111
+ @keyframes ps-pm-age-gate-in {
13112
+ 0% { opacity: 0; transform: scale(0.97); }
13113
+ 100% { opacity: 1; transform: scale(1); }
13114
+ }
13115
+ .ps-pm-age-gate-card {
13116
+ width: 100%; max-width: max(280px, 82vw);
13117
+ padding: max(18px, 4.6vw) max(16px, 4.2vw);
13118
+ background: #FFFFFF;
13119
+ border: 1px solid var(--ps-border-subtle);
13120
+ border-radius: max(12px, 3vw);
13121
+ box-shadow: 0 20px 40px -12px rgba(17, 24, 39, 0.25),
13122
+ 0 8px 16px -8px rgba(17, 24, 39, 0.15);
13123
+ display: flex; flex-direction: column;
13124
+ align-items: center; text-align: center;
13125
+ gap: max(8px, 2vw);
13126
+ }
13127
+ .ps-pm-age-gate-eyebrow {
13128
+ font-size: max(10px, 2.6vw); font-weight: 700;
13129
+ letter-spacing: 0.14em; text-transform: uppercase;
13130
+ color: var(--ps-accent);
13131
+ }
13132
+ .ps-pm-age-gate-eyebrow-blocked { color: #C02626; }
13133
+ .ps-pm-age-gate-question {
13134
+ font-size: max(14px, 3.8vw); font-weight: 600;
13135
+ line-height: 1.35; color: var(--ps-text-primary); margin: 0;
13136
+ }
13137
+ .ps-pm-age-gate-actions {
13138
+ display: flex; flex-direction: column; gap: max(8px, 2vw);
13139
+ width: 100%; margin-top: max(4px, 1vw);
13140
+ }
13141
+ .ps-pm-age-gate-btn {
13142
+ width: 100%;
13143
+ padding: max(11px, 2.9vw) max(14px, 3.6vw);
13144
+ border-radius: 999px;
13145
+ font-family: inherit;
13146
+ font-size: max(12px, 3.2vw); font-weight: 700;
13147
+ letter-spacing: 0.02em;
13148
+ cursor: pointer;
13149
+ transition: background 0.18s, border-color 0.18s, color 0.18s;
13150
+ }
13151
+ .ps-pm-age-gate-btn-primary {
13152
+ background: var(--ps-accent);
13153
+ color: #FFFFFF;
13154
+ border: 1.5px solid var(--ps-accent);
13155
+ }
13156
+ .ps-pm-age-gate-btn-secondary {
13157
+ background: transparent;
13158
+ color: var(--ps-text-primary);
13159
+ border: 1.5px solid var(--ps-border-color);
13160
+ }
13161
+ .ps-pm-age-gate-btn-secondary:active {
13162
+ background: var(--ps-bg-secondary);
13163
+ }
13164
+
13165
+ /* ── Mobile legal notice ── */
13166
+ .ps-pm-legal-notice {
13167
+ margin-top: max(10px, 2.6vw);
13168
+ background: rgba(33, 84, 239, 0.04);
13169
+ border: 1px solid rgba(33, 84, 239, 0.16);
13170
+ border-radius: max(10px, 2.6vw);
13171
+ padding: max(10px, 2.6vw) max(12px, 3.1vw);
13172
+ display: flex; flex-direction: column;
13173
+ gap: max(4px, 1vw);
13174
+ }
13175
+ .ps-pm-legal-notice-head {
13176
+ display: flex; align-items: center;
13177
+ gap: max(6px, 1.5vw);
13178
+ font-size: max(10px, 2.6vw); font-weight: 700;
13179
+ letter-spacing: 0.12em; text-transform: uppercase;
13180
+ color: var(--ps-accent);
13181
+ }
13182
+ .ps-pm-legal-notice-head svg { width: max(13px, 3.4vw); height: max(13px, 3.4vw); }
13183
+ .ps-pm-legal-notice-body {
13184
+ margin: 0;
13185
+ font-size: max(11px, 2.9vw);
13186
+ line-height: 1.5;
13187
+ color: var(--ps-text-secondary);
13188
+ }
13189
+
13095
13190
  /* Checklist for accuracy card */
13096
13191
  .ps-pm-checklist {
13097
13192
  display: flex; gap: max(12px, 3.1vw);
@@ -14953,6 +15048,127 @@ const STYLES$1 = `
14953
15048
  transition: background 0.18s;
14954
15049
  }
14955
15050
  .ps-cpw-photo-retake:hover { background: rgba(33, 84, 239, 0.08); }
15051
+
15052
+ /* ── Age-gate overlay on the dropzone ──
15053
+ Dropzone stays visible but blurred; overlay shows a premium card
15054
+ with the 18+ confirmation question and two pill buttons. */
15055
+ .ps-cpw-dropzone-wrap {
15056
+ position: relative;
15057
+ flex: 1; min-height: 0;
15058
+ width: 100%; box-sizing: border-box;
15059
+ display: flex; flex-direction: column;
15060
+ }
15061
+ .ps-cpw-dropzone-blurred {
15062
+ filter: blur(6px) saturate(0.7);
15063
+ pointer-events: none;
15064
+ user-select: none;
15065
+ }
15066
+ .ps-cpw-age-gate {
15067
+ position: absolute; inset: 0;
15068
+ display: flex; align-items: center; justify-content: center;
15069
+ padding: clamp(12px, 1vw, 24px);
15070
+ border-radius: clamp(10px, 0.75vw, 16px);
15071
+ background: rgba(255, 255, 255, 0.55);
15072
+ backdrop-filter: blur(8px);
15073
+ -webkit-backdrop-filter: blur(8px);
15074
+ z-index: 2;
15075
+ animation: ps-cpw-age-gate-in 0.28s ease-out both;
15076
+ }
15077
+ @keyframes ps-cpw-age-gate-in {
15078
+ 0% { opacity: 0; transform: scale(0.97); }
15079
+ 100% { opacity: 1; transform: scale(1); }
15080
+ }
15081
+ .ps-cpw-age-gate-card {
15082
+ width: 100%; max-width: clamp(240px, 24vw, 420px);
15083
+ padding: clamp(16px, 1.4vw, 28px) clamp(18px, 1.6vw, 32px);
15084
+ background: #FFFFFF;
15085
+ border: 1px solid var(--ps-border-subtle);
15086
+ border-radius: clamp(10px, 0.9vw, 18px);
15087
+ box-shadow: 0 20px 40px -12px rgba(17, 24, 39, 0.25),
15088
+ 0 8px 16px -8px rgba(17, 24, 39, 0.15);
15089
+ display: flex; flex-direction: column;
15090
+ align-items: center; text-align: center;
15091
+ gap: clamp(8px, 0.7vw, 14px);
15092
+ }
15093
+ .ps-cpw-age-gate-eyebrow {
15094
+ font-size: clamp(9px, 0.62vw, 11px);
15095
+ font-weight: 700;
15096
+ letter-spacing: 0.18em;
15097
+ text-transform: uppercase;
15098
+ color: var(--ps-accent);
15099
+ }
15100
+ .ps-cpw-age-gate-eyebrow-blocked { color: #C02626; }
15101
+ .ps-cpw-age-gate-question {
15102
+ font-size: clamp(13px, 0.95vw, 18px);
15103
+ font-weight: 600;
15104
+ line-height: 1.35;
15105
+ color: var(--ps-text-primary);
15106
+ margin: 0;
15107
+ }
15108
+ .ps-cpw-age-gate-actions {
15109
+ display: flex; gap: clamp(8px, 0.65vw, 14px);
15110
+ width: 100%;
15111
+ margin-top: clamp(4px, 0.35vw, 8px);
15112
+ }
15113
+ .ps-cpw-age-gate-btn {
15114
+ flex: 1;
15115
+ padding: clamp(9px, 0.75vw, 14px) clamp(12px, 1vw, 18px);
15116
+ border-radius: 999px;
15117
+ font-family: inherit;
15118
+ font-size: clamp(11px, 0.78vw, 14px);
15119
+ font-weight: 700;
15120
+ letter-spacing: 0.02em;
15121
+ cursor: pointer;
15122
+ transition: transform 0.18s, background 0.18s, border-color 0.18s, color 0.18s;
15123
+ }
15124
+ .ps-cpw-age-gate-btn:hover { transform: translateY(-1px); }
15125
+ .ps-cpw-age-gate-btn-primary {
15126
+ background: var(--ps-accent);
15127
+ color: #FFFFFF;
15128
+ border: 1.5px solid var(--ps-accent);
15129
+ }
15130
+ .ps-cpw-age-gate-btn-primary:hover { background: color-mix(in srgb, var(--ps-accent) 88%, #000); }
15131
+ .ps-cpw-age-gate-btn-secondary {
15132
+ background: transparent;
15133
+ color: var(--ps-text-primary);
15134
+ border: 1.5px solid var(--ps-border-color);
15135
+ }
15136
+ .ps-cpw-age-gate-btn-secondary:hover {
15137
+ background: var(--ps-bg-secondary);
15138
+ border-color: var(--ps-text-muted);
15139
+ }
15140
+ .ps-cpw-age-gate-card-blocked { border-color: rgba(192, 38, 38, 0.35); }
15141
+
15142
+ /* ── Legal notice card on the right column ──
15143
+ Soft neutral card with a small shield icon; matches photo-guide width. */
15144
+ .ps-cpw-legal-notice {
15145
+ background: rgba(33, 84, 239, 0.04);
15146
+ border: 1px solid rgba(33, 84, 239, 0.16);
15147
+ border-radius: clamp(10px, 0.75vw, 16px);
15148
+ padding: clamp(10px, 0.9vw, 18px) clamp(12px, 1vw, 20px);
15149
+ display: flex; flex-direction: column;
15150
+ gap: clamp(5px, 0.45vw, 10px);
15151
+ }
15152
+ .ps-cpw-legal-notice-head {
15153
+ display: flex; align-items: center;
15154
+ gap: clamp(6px, 0.5vw, 10px);
15155
+ font-size: clamp(9px, 0.62vw, 11px);
15156
+ font-weight: 700;
15157
+ letter-spacing: 0.14em;
15158
+ text-transform: uppercase;
15159
+ color: var(--ps-accent);
15160
+ }
15161
+ .ps-cpw-legal-notice-head svg {
15162
+ width: clamp(12px, 0.85vw, 15px);
15163
+ height: clamp(12px, 0.85vw, 15px);
15164
+ }
15165
+ .ps-cpw-legal-notice-body {
15166
+ margin: 0;
15167
+ font-size: clamp(10px, 0.7vw, 12.5px);
15168
+ line-height: 1.5;
15169
+ color: var(--ps-text-secondary);
15170
+ }
15171
+
14956
15172
  .ps-cpw-hint {
14957
15173
  font-size: clamp(10px, 0.72vw, 13px);
14958
15174
  line-height: 1.6;
@@ -16870,6 +17086,102 @@ const SKELETON_CONNECTIONS = [
16870
17086
  ["rightHip", "rightKnee"],
16871
17087
  ["rightKnee", "rightAnkle"]
16872
17088
  ];
17089
+ function FaceOverlay({
17090
+ landmarks,
17091
+ imgWidth,
17092
+ imgHeight
17093
+ }) {
17094
+ const W2 = imgWidth;
17095
+ const H2 = imgHeight;
17096
+ const pts = [
17097
+ { key: "forehead", p: landmarks.forehead },
17098
+ { key: "chin", p: landmarks.chin },
17099
+ { key: "noseTip", p: landmarks.noseTip },
17100
+ { key: "noseBridge", p: landmarks.noseBridge },
17101
+ { key: "leftInnerEye", p: landmarks.leftInnerEye },
17102
+ { key: "rightInnerEye", p: landmarks.rightInnerEye },
17103
+ { key: "leftOuterEye", p: landmarks.leftOuterEye },
17104
+ { key: "rightOuterEye", p: landmarks.rightOuterEye },
17105
+ { key: "leftTragus", p: landmarks.leftTragus },
17106
+ { key: "rightTragus", p: landmarks.rightTragus },
17107
+ { key: "leftMouth", p: landmarks.leftMouth },
17108
+ { key: "rightMouth", p: landmarks.rightMouth }
17109
+ ];
17110
+ const connections = [
17111
+ // Face axis
17112
+ [landmarks.forehead, landmarks.noseBridge],
17113
+ [landmarks.noseBridge, landmarks.noseTip],
17114
+ [landmarks.noseTip, landmarks.chin],
17115
+ // Horizontal eye line
17116
+ [landmarks.leftOuterEye, landmarks.leftInnerEye],
17117
+ [landmarks.leftInnerEye, landmarks.rightInnerEye],
17118
+ [landmarks.rightInnerEye, landmarks.rightOuterEye],
17119
+ // Ears
17120
+ [landmarks.leftTragus, landmarks.leftOuterEye],
17121
+ [landmarks.rightOuterEye, landmarks.rightTragus],
17122
+ // Mouth line
17123
+ [landmarks.leftMouth, landmarks.rightMouth]
17124
+ ];
17125
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className: "ps-tryon-pose-overlay", viewBox: `0 0 ${W2} ${H2}`, preserveAspectRatio: "xMidYMid meet", children: [
17126
+ connections.map(([a, b], i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
17127
+ "line",
17128
+ {
17129
+ x1: a.x * W2,
17130
+ y1: a.y * H2,
17131
+ x2: b.x * W2,
17132
+ y2: b.y * H2,
17133
+ stroke: "rgba(100,210,255,0.55)",
17134
+ strokeWidth: "3",
17135
+ strokeLinecap: "round",
17136
+ opacity: "0",
17137
+ style: { animation: `ps-pose-fade 0.4s ease ${i * 0.05}s forwards` }
17138
+ },
17139
+ `fl-${i}`
17140
+ )),
17141
+ [landmarks.leftIrisCenter, landmarks.rightIrisCenter].map((c, i) => {
17142
+ const ring = i === 0 ? landmarks.leftIrisRing : landmarks.rightIrisRing;
17143
+ const rx = ring?.length ? Math.abs((ring[0]?.x ?? c.x) - (ring[2]?.x ?? c.x)) * W2 / 2 : 6;
17144
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
17145
+ "circle",
17146
+ {
17147
+ cx: c.x * W2,
17148
+ cy: c.y * H2,
17149
+ r: Math.max(6, rx),
17150
+ fill: "none",
17151
+ stroke: "rgba(255,230,120,0.95)",
17152
+ strokeWidth: "2.5",
17153
+ opacity: "0",
17154
+ style: { animation: `ps-pose-fade 0.3s ease ${0.3 + i * 0.1}s forwards` }
17155
+ },
17156
+ `iris-${i}`
17157
+ );
17158
+ }),
17159
+ pts.map(({ key, p: p2 }, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
17160
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17161
+ "circle",
17162
+ {
17163
+ cx: p2.x * W2,
17164
+ cy: p2.y * H2,
17165
+ r: "11",
17166
+ fill: "rgba(100,210,255,0.22)",
17167
+ opacity: "0",
17168
+ style: { animation: `ps-pose-fade 0.3s ease ${i * 0.04}s forwards` }
17169
+ }
17170
+ ),
17171
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17172
+ "circle",
17173
+ {
17174
+ cx: p2.x * W2,
17175
+ cy: p2.y * H2,
17176
+ r: "6",
17177
+ fill: "rgba(100,210,255,0.95)",
17178
+ opacity: "0",
17179
+ style: { animation: `ps-pose-fade 0.3s ease ${i * 0.04}s forwards, ps-dot-pulse 1.5s ease-in-out ${0.5 + i * 0.04}s infinite` }
17180
+ }
17181
+ )
17182
+ ] }, key))
17183
+ ] });
17184
+ }
16873
17185
  function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
16874
17186
  const W2 = imgWidth;
16875
17187
  const H2 = imgHeight;
@@ -17734,6 +18046,8 @@ function SizeResultView({
17734
18046
  handleTryOnSubmit,
17735
18047
  tryOnProcessing,
17736
18048
  bodyLandmarks,
18049
+ faceLandmarks = null,
18050
+ measurementType = "body",
17737
18051
  estimationDone = false,
17738
18052
  activeSection,
17739
18053
  setActiveSection,
@@ -18020,28 +18334,33 @@ function SizeResultView({
18020
18334
  onLoad: handleImgLoad
18021
18335
  }
18022
18336
  ),
18023
- bodyLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h })
18337
+ measurementType === "face" || measurementType === "head" ? faceLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(FaceOverlay, { landmarks: faceLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h }) : bodyLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h })
18024
18338
  ] }),
18025
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
18026
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${bodyLandmarks ? " ps-done" : " ps-active"}`, children: [
18027
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: bodyLandmarks ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18028
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Detecting body pose") })
18029
- ] }),
18030
- !sizingDone && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
18031
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : bodyLandmarks ? " ps-active" : ""}`, children: [
18032
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !bodyLandmarks ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
18033
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Analyzing your size") })
18339
+ (() => {
18340
+ const isFaceCategory = measurementType === "face" || measurementType === "head";
18341
+ const detectionDone = isFaceCategory ? !!faceLandmarks : !!bodyLandmarks;
18342
+ const detectLabel = isFaceCategory ? measurementType === "head" ? t2("Detecting head") : t2("Detecting face") : t2("Detecting body pose");
18343
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
18344
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${detectionDone ? " ps-done" : " ps-active"}`, children: [
18345
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: detectionDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18346
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: detectLabel })
18347
+ ] }),
18348
+ !sizingDone && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
18349
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
18350
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
18351
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Analyzing your size") })
18352
+ ] }),
18353
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
18354
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Finding best fit for you") })
18356
+ ] })
18034
18357
  ] }),
18035
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
18036
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18037
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Finding best fit for you") })
18358
+ tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
18359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18360
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Generating virtual try-on") })
18038
18361
  ] })
18039
- ] }),
18040
- tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
18041
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
18042
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Generating virtual try-on") })
18043
- ] })
18044
- ] })
18362
+ ] });
18363
+ })()
18045
18364
  ] }),
18046
18365
  (allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
18047
18366
  isMultiSection ? activeSection ? (
@@ -18840,9 +19159,18 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t:
18840
19159
  const photoInputRef = reactExports.useRef(null);
18841
19160
  const nameInputRef = reactExports.useRef(null);
18842
19161
  const [nameShaking, setNameShaking] = reactExports.useState(false);
19162
+ const [ageConfirmed, setAgeConfirmed] = reactExports.useState(null);
19163
+ const openFilePicker = () => {
19164
+ if (ageConfirmed !== true) return;
19165
+ photoInputRef.current?.click();
19166
+ };
18843
19167
  const handlePhotoSelect = async (e) => {
18844
19168
  const file = e.target.files?.[0];
18845
19169
  if (!file) return;
19170
+ if (ageConfirmed !== true) {
19171
+ setError(t2("Please confirm that the person in the photo is 18 or older before uploading."));
19172
+ return;
19173
+ }
18846
19174
  if (!file.type.startsWith("image/")) {
18847
19175
  setError(t2("Please upload an image file"));
18848
19176
  return;
@@ -19423,18 +19751,71 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t:
19423
19751
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-image-left", children: photoBase64 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-photo-preview-frame", children: [
19424
19752
  /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: photoBase64, alt: t2("Profile photo"), className: "ps-cpw-photo-preview-img" }),
19425
19753
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-photo-remove", onClick: handleRemovePhoto, "aria-label": t2("Remove photo"), children: "×" }),
19426
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-photo-retake-pill", onClick: () => photoInputRef.current?.click(), children: t2("Retake") })
19427
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-cpw-dropzone", onClick: () => photoInputRef.current?.click(), disabled: photoUploading, children: [
19428
- /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: photoUploadIllustrationImg, alt: "", "aria-hidden": "true", className: "ps-cpw-dropzone-silhouette" }),
19429
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-dropzone-content", children: [
19430
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className: "ps-cpw-dropzone-upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
19431
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
19432
- /* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }),
19433
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
19434
- ] }),
19435
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-cpw-dropzone-title", children: photoUploading ? t2("Processing...") : t2("Drop a photo or click to upload") }),
19436
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-cpw-dropzone-hint", children: t2("JPEG · PNG · WebP · up to 10MB") })
19437
- ] })
19754
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-photo-retake-pill", onClick: openFilePicker, children: t2("Retake") })
19755
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-dropzone-wrap", children: [
19756
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
19757
+ "button",
19758
+ {
19759
+ type: "button",
19760
+ className: `ps-cpw-dropzone${ageConfirmed !== true ? " ps-cpw-dropzone-blurred" : ""}`,
19761
+ onClick: openFilePicker,
19762
+ disabled: photoUploading || ageConfirmed !== true,
19763
+ "aria-hidden": ageConfirmed !== true,
19764
+ tabIndex: ageConfirmed !== true ? -1 : 0,
19765
+ children: [
19766
+ /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: photoUploadIllustrationImg, alt: "", "aria-hidden": "true", className: "ps-cpw-dropzone-silhouette" }),
19767
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-dropzone-content", children: [
19768
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className: "ps-cpw-dropzone-upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
19769
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
19770
+ /* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "17 8 12 3 7 8" }),
19771
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
19772
+ ] }),
19773
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-cpw-dropzone-title", children: photoUploading ? t2("Processing...") : t2("Drop a photo or click to upload") }),
19774
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-cpw-dropzone-hint", children: t2("JPEG · PNG · WebP · up to 10MB") })
19775
+ ] })
19776
+ ]
19777
+ }
19778
+ ),
19779
+ ageConfirmed === null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-age-gate", role: "dialog", "aria-labelledby": "ps-cpw-age-gate-q", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-age-gate-card", children: [
19780
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-age-gate-eyebrow", children: t2("AGE VERIFICATION") }),
19781
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: "ps-cpw-age-gate-q", className: "ps-cpw-age-gate-question", children: t2("Is the person in this photo 18 years or older?") }),
19782
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-age-gate-actions", children: [
19783
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
19784
+ "button",
19785
+ {
19786
+ type: "button",
19787
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-primary",
19788
+ onClick: () => {
19789
+ setAgeConfirmed(true);
19790
+ setError("");
19791
+ },
19792
+ children: t2("Yes, 18 or older")
19793
+ }
19794
+ ),
19795
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
19796
+ "button",
19797
+ {
19798
+ type: "button",
19799
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-secondary",
19800
+ onClick: () => setAgeConfirmed(false),
19801
+ children: t2("No, under 18")
19802
+ }
19803
+ )
19804
+ ] })
19805
+ ] }) }),
19806
+ ageConfirmed === false && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-age-gate", role: "alert", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-age-gate-card ps-cpw-age-gate-card-blocked", children: [
19807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-age-gate-eyebrow ps-cpw-age-gate-eyebrow-blocked", children: t2("UPLOAD NOT ALLOWED") }),
19808
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-age-gate-question", children: t2("For your safety, we cannot process photos of people under 18.") }),
19809
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
19810
+ "button",
19811
+ {
19812
+ type: "button",
19813
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-secondary",
19814
+ onClick: () => setAgeConfirmed(null),
19815
+ children: t2("Go back")
19816
+ }
19817
+ )
19818
+ ] }) })
19438
19819
  ] }) }),
19439
19820
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-image-right", children: [
19440
19821
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-fields ps-cpw-inline-fields", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
@@ -19465,6 +19846,13 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t:
19465
19846
  ] })
19466
19847
  ] })
19467
19848
  ] }),
19849
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-legal-notice", children: [
19850
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-legal-notice-head", children: [
19851
+ /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }),
19852
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("LEGAL NOTICE") })
19853
+ ] }),
19854
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-cpw-legal-notice-body", children: t2("Your image will be used to generate a virtual try-on preview showing how selected items may look and fit. Images are processed securely and are not stored after generation.") })
19855
+ ] }),
19468
19856
  error && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-error", children: error })
19469
19857
  ] })
19470
19858
  ] }, "image-photo"),
@@ -20308,6 +20696,8 @@ function PhotoStepMobile({
20308
20696
  const isCloseUp = photoVariant === "close-up";
20309
20697
  const fileRef = reactExports.useRef(null);
20310
20698
  const hasPhoto = !!photoPreview;
20699
+ const [ageConfirmed, setAgeConfirmed] = reactExports.useState(null);
20700
+ const gated = !hasPhoto && ageConfirmed !== true;
20311
20701
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-root", children: [
20312
20702
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-header", children: [
20313
20703
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-pm-title", children: isCloseUp ? t2("Upload a face photo or selfie") : t2("Review your photo") }),
@@ -20335,19 +20725,46 @@ function PhotoStepMobile({
20335
20725
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIconSm, {})
20336
20726
  }
20337
20727
  )
20338
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
20339
- "button",
20340
- {
20341
- type: "button",
20342
- className: "ps-pm-preview-empty",
20343
- onClick: () => fileRef.current?.click(),
20344
- children: [
20345
- /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIconLg, {}),
20346
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-pm-preview-empty-title", children: t2("Tap to upload") }),
20347
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-pm-preview-empty-hint", children: t2("JPEG, PNG up to 10MB") })
20348
- ]
20349
- }
20350
- ) }),
20728
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
20729
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
20730
+ "button",
20731
+ {
20732
+ type: "button",
20733
+ className: `ps-pm-preview-empty${gated ? " ps-pm-preview-blurred" : ""}`,
20734
+ onClick: () => {
20735
+ if (!gated) fileRef.current?.click();
20736
+ },
20737
+ disabled: gated,
20738
+ "aria-hidden": gated,
20739
+ tabIndex: gated ? -1 : 0,
20740
+ children: [
20741
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIconLg, {}),
20742
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-pm-preview-empty-title", children: t2("Tap to upload") }),
20743
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-pm-preview-empty-hint", children: t2("JPEG, PNG up to 10MB") })
20744
+ ]
20745
+ }
20746
+ ),
20747
+ ageConfirmed === null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate", role: "dialog", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-age-gate-card", children: [
20748
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-eyebrow", children: t2("AGE VERIFICATION") }),
20749
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-question", children: t2("Is the person in this photo 18 years or older?") }),
20750
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-age-gate-actions", children: [
20751
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-primary", onClick: () => setAgeConfirmed(true), children: t2("Yes, 18 or older") }),
20752
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => setAgeConfirmed(false), children: t2("No, under 18") })
20753
+ ] })
20754
+ ] }) }),
20755
+ ageConfirmed === false && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate", role: "alert", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-age-gate-card", children: [
20756
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-eyebrow ps-pm-age-gate-eyebrow-blocked", children: t2("UPLOAD NOT ALLOWED") }),
20757
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-question", children: t2("For your safety, we cannot process photos of people under 18.") }),
20758
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => setAgeConfirmed(null), children: t2("Go back") })
20759
+ ] }) })
20760
+ ] }) }),
20761
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-legal-notice", children: [
20762
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-legal-notice-head", children: [
20763
+ /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }),
20764
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("LEGAL NOTICE") })
20765
+ ] }),
20766
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-pm-legal-notice-body", children: t2("Your image will be used to generate a virtual try-on preview showing how selected items may look and fit. Images are processed securely and are not stored after generation.") })
20767
+ ] }),
20351
20768
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-checklist", children: [
20352
20769
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-checklist-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoIcon, {}) }),
20353
20770
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-checklist-body", children: [
@@ -20595,6 +21012,7 @@ function BodyProfileView({
20595
21012
  const [photoBase64, setPhotoBase64] = reactExports.useState(null);
20596
21013
  const [photoProcessing, setPhotoProcessing] = reactExports.useState(false);
20597
21014
  const fileInputRef = reactExports.useRef(null);
21015
+ const [ageConfirmed, setAgeConfirmed] = reactExports.useState(null);
20598
21016
  const [photoStepHeight, setPhotoStepHeight] = reactExports.useState(() => {
20599
21017
  if (seedTotalIn != null) return String(Math.round(seedTotalIn * 2.54));
20600
21018
  return seedHeightCm;
@@ -20619,6 +21037,10 @@ function BodyProfileView({
20619
21037
  const handlePhotoSelect = reactExports.useCallback(async (e) => {
20620
21038
  const file = e.target.files?.[0];
20621
21039
  if (!file) return;
21040
+ if (ageConfirmed !== true) {
21041
+ setError(t2("Please confirm that the person in the photo is 18 or older before uploading."));
21042
+ return;
21043
+ }
20622
21044
  if (!file.type.startsWith("image/")) {
20623
21045
  setError(t2("Please upload an image file"));
20624
21046
  return;
@@ -20641,7 +21063,7 @@ function BodyProfileView({
20641
21063
  } finally {
20642
21064
  setPhotoProcessing(false);
20643
21065
  }
20644
- }, [t2]);
21066
+ }, [t2, ageConfirmed]);
20645
21067
  const handleRemovePhoto = reactExports.useCallback(() => {
20646
21068
  if (photoPreview) URL.revokeObjectURL(photoPreview);
20647
21069
  setPhotoFile(null);
@@ -20807,38 +21229,186 @@ function BodyProfileView({
20807
21229
  }
20808
21230
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-wrapper", children: [
20809
21231
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: "1.2vw", padding: "1.5vw", width: "100%", height: "100%", minHeight: "20vw", alignItems: "stretch" }, children: [
20810
- /* @__PURE__ */ jsxRuntimeExports.jsx(
20811
- "div",
20812
- {
20813
- onClick: () => !photoPreview && fileInputRef.current?.click(),
20814
- style: {
20815
- flex: 1,
20816
- display: "flex",
20817
- flexDirection: "column",
20818
- alignItems: "center",
20819
- justifyContent: "center",
20820
- border: photoPreview ? "2px solid var(--ps-accent)" : "2px dashed var(--ps-border-color)",
20821
- borderRadius: "0.5vw",
20822
- cursor: photoPreview ? "default" : "pointer",
20823
- position: "relative",
20824
- background: "var(--ps-bg-secondary)",
20825
- transition: "border-color 0.2s",
20826
- overflow: "hidden"
20827
- },
20828
- children: photoPreview ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
20829
- /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: photoPreview, alt: "preview", style: { width: "100%", height: "100%", objectFit: "contain" } }),
20830
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
20831
- e.stopPropagation();
20832
- handleRemovePhoto();
20833
- }, style: { position: "absolute", top: "0.5vw", right: "0.5vw", width: "1.4vw", height: "1.4vw", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "none", color: "#fff", fontSize: "0.7vw", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }, children: "×" })
20834
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
20835
- /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIcon, { size: 32 }),
20836
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.85vw", fontWeight: 600, color: "var(--ps-text-primary)", marginTop: "0.5vw" }, children: t2("Upload your photo") }),
20837
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", color: "var(--ps-text-muted)", marginTop: "0.2vw" }, children: t2("Click or drag a full-body photo") }),
20838
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.5vw", color: "var(--ps-text-dim)", marginTop: "0.4vw" }, children: "JPEG, PNG (max 10MB)" })
20839
- ] })
20840
- }
20841
- ),
21232
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { flex: 1, position: "relative", display: "flex" }, children: [
21233
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
21234
+ "div",
21235
+ {
21236
+ onClick: () => {
21237
+ if (!photoPreview && ageConfirmed === true) fileInputRef.current?.click();
21238
+ },
21239
+ style: {
21240
+ flex: 1,
21241
+ display: "flex",
21242
+ flexDirection: "column",
21243
+ alignItems: "center",
21244
+ justifyContent: "center",
21245
+ border: photoPreview ? "2px solid var(--ps-accent)" : "2px dashed var(--ps-border-color)",
21246
+ borderRadius: "0.5vw",
21247
+ cursor: photoPreview ? "default" : ageConfirmed === true ? "pointer" : "not-allowed",
21248
+ position: "relative",
21249
+ background: "var(--ps-bg-secondary)",
21250
+ transition: "border-color 0.2s, filter 0.25s",
21251
+ overflow: "hidden",
21252
+ filter: !photoPreview && ageConfirmed !== true ? "blur(6px) saturate(0.7)" : void 0,
21253
+ pointerEvents: !photoPreview && ageConfirmed !== true ? "none" : void 0,
21254
+ userSelect: !photoPreview && ageConfirmed !== true ? "none" : void 0
21255
+ },
21256
+ "aria-hidden": !photoPreview && ageConfirmed !== true,
21257
+ children: photoPreview ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
21258
+ /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: photoPreview, alt: "preview", style: { width: "100%", height: "100%", objectFit: "contain" } }),
21259
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: (e) => {
21260
+ e.stopPropagation();
21261
+ handleRemovePhoto();
21262
+ }, style: { position: "absolute", top: "0.5vw", right: "0.5vw", width: "1.4vw", height: "1.4vw", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "none", color: "#fff", fontSize: "0.7vw", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }, children: "×" })
21263
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
21264
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIcon, { size: 32 }),
21265
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.85vw", fontWeight: 600, color: "var(--ps-text-primary)", marginTop: "0.5vw" }, children: t2("Upload your photo") }),
21266
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", color: "var(--ps-text-muted)", marginTop: "0.2vw" }, children: t2("Click or drag a full-body photo") }),
21267
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.5vw", color: "var(--ps-text-dim)", marginTop: "0.4vw" }, children: "JPEG, PNG (max 10MB)" })
21268
+ ] })
21269
+ }
21270
+ ),
21271
+ !photoPreview && ageConfirmed === null && /* @__PURE__ */ jsxRuntimeExports.jsx(
21272
+ "div",
21273
+ {
21274
+ role: "dialog",
21275
+ "aria-labelledby": "ps-bp-age-q",
21276
+ style: {
21277
+ position: "absolute",
21278
+ inset: 0,
21279
+ display: "flex",
21280
+ alignItems: "center",
21281
+ justifyContent: "center",
21282
+ padding: "1vw",
21283
+ background: "rgba(255,255,255,0.55)",
21284
+ backdropFilter: "blur(8px)",
21285
+ WebkitBackdropFilter: "blur(8px)",
21286
+ borderRadius: "0.5vw",
21287
+ zIndex: 2,
21288
+ animation: "ps-cpw-age-gate-in 0.28s ease-out both"
21289
+ },
21290
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: {
21291
+ width: "100%",
21292
+ maxWidth: "min(420px, 22vw)",
21293
+ padding: "1.4vw 1.6vw",
21294
+ background: "#FFFFFF",
21295
+ border: "1px solid var(--ps-border-subtle)",
21296
+ borderRadius: "0.9vw",
21297
+ boxShadow: "0 20px 40px -12px rgba(17,24,39,0.25), 0 8px 16px -8px rgba(17,24,39,0.15)",
21298
+ display: "flex",
21299
+ flexDirection: "column",
21300
+ alignItems: "center",
21301
+ textAlign: "center",
21302
+ gap: "0.75vw"
21303
+ }, children: [
21304
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.62vw", fontWeight: 700, letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--ps-accent)" }, children: t2("AGE VERIFICATION") }),
21305
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: "ps-bp-age-q", style: { fontSize: "0.95vw", fontWeight: 600, lineHeight: 1.35, color: "var(--ps-text-primary)" }, children: t2("Is the person in this photo 18 years or older?") }),
21306
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: "0.65vw", width: "100%", marginTop: "0.4vw" }, children: [
21307
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
21308
+ "button",
21309
+ {
21310
+ type: "button",
21311
+ onClick: () => {
21312
+ setAgeConfirmed(true);
21313
+ setError("");
21314
+ },
21315
+ style: {
21316
+ flex: 1,
21317
+ padding: "0.75vw 1vw",
21318
+ borderRadius: "999px",
21319
+ background: "var(--ps-accent)",
21320
+ color: "#FFFFFF",
21321
+ border: "1.5px solid var(--ps-accent)",
21322
+ fontFamily: "inherit",
21323
+ fontSize: "0.78vw",
21324
+ fontWeight: 700,
21325
+ cursor: "pointer",
21326
+ transition: "transform 0.18s, background 0.18s"
21327
+ },
21328
+ children: t2("Yes, 18 or older")
21329
+ }
21330
+ ),
21331
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
21332
+ "button",
21333
+ {
21334
+ type: "button",
21335
+ onClick: () => setAgeConfirmed(false),
21336
+ style: {
21337
+ flex: 1,
21338
+ padding: "0.75vw 1vw",
21339
+ borderRadius: "999px",
21340
+ background: "transparent",
21341
+ color: "var(--ps-text-primary)",
21342
+ border: "1.5px solid var(--ps-border-color)",
21343
+ fontFamily: "inherit",
21344
+ fontSize: "0.78vw",
21345
+ fontWeight: 700,
21346
+ cursor: "pointer",
21347
+ transition: "background 0.18s, border-color 0.18s"
21348
+ },
21349
+ children: t2("No, under 18")
21350
+ }
21351
+ )
21352
+ ] })
21353
+ ] })
21354
+ }
21355
+ ),
21356
+ !photoPreview && ageConfirmed === false && /* @__PURE__ */ jsxRuntimeExports.jsx(
21357
+ "div",
21358
+ {
21359
+ role: "alert",
21360
+ style: {
21361
+ position: "absolute",
21362
+ inset: 0,
21363
+ display: "flex",
21364
+ alignItems: "center",
21365
+ justifyContent: "center",
21366
+ padding: "1vw",
21367
+ background: "rgba(255,255,255,0.55)",
21368
+ backdropFilter: "blur(8px)",
21369
+ WebkitBackdropFilter: "blur(8px)",
21370
+ borderRadius: "0.5vw",
21371
+ zIndex: 2
21372
+ },
21373
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: {
21374
+ width: "100%",
21375
+ maxWidth: "min(420px, 22vw)",
21376
+ padding: "1.4vw 1.6vw",
21377
+ background: "#FFFFFF",
21378
+ border: "1px solid rgba(192,38,38,0.35)",
21379
+ borderRadius: "0.9vw",
21380
+ boxShadow: "0 20px 40px -12px rgba(17,24,39,0.25)",
21381
+ display: "flex",
21382
+ flexDirection: "column",
21383
+ alignItems: "center",
21384
+ textAlign: "center",
21385
+ gap: "0.75vw"
21386
+ }, children: [
21387
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.62vw", fontWeight: 700, letterSpacing: "0.18em", textTransform: "uppercase", color: "#C02626" }, children: t2("UPLOAD NOT ALLOWED") }),
21388
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.95vw", fontWeight: 600, lineHeight: 1.35, color: "var(--ps-text-primary)" }, children: t2("For your safety, we cannot process photos of people under 18.") }),
21389
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
21390
+ "button",
21391
+ {
21392
+ type: "button",
21393
+ onClick: () => setAgeConfirmed(null),
21394
+ style: {
21395
+ padding: "0.75vw 1.4vw",
21396
+ borderRadius: "999px",
21397
+ background: "transparent",
21398
+ color: "var(--ps-text-primary)",
21399
+ border: "1.5px solid var(--ps-border-color)",
21400
+ fontFamily: "inherit",
21401
+ fontSize: "0.78vw",
21402
+ fontWeight: 700,
21403
+ cursor: "pointer"
21404
+ },
21405
+ children: t2("Go back")
21406
+ }
21407
+ )
21408
+ ] })
21409
+ }
21410
+ )
21411
+ ] }),
20842
21412
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: "0.6vw", justifyContent: "center" }, children: [
20843
21413
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.85vw", fontWeight: 700, color: "var(--ps-text-primary)", marginBottom: "0.3vw" }, children: t2("How to take the best photo") }),
20844
21414
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "#ddfbe7", borderRadius: "0.5vw", padding: "0.6vw 0.8vw" }, children: [
@@ -20881,6 +21451,21 @@ function BodyProfileView({
20881
21451
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#3267c3", fontSize: "0.65vw", fontWeight: 600 }, children: t2("Quick Tip") })
20882
21452
  ] }),
20883
21453
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.58vw", color: "var(--ps-text-primary)", lineHeight: 1.6 }, children: t2("The simpler your photo is, the more accurate your virtual try-on results will be.") })
21454
+ ] }),
21455
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: {
21456
+ background: "rgba(33, 84, 239, 0.04)",
21457
+ border: "1px solid rgba(33, 84, 239, 0.16)",
21458
+ borderRadius: "0.5vw",
21459
+ padding: "0.6vw 0.8vw",
21460
+ display: "flex",
21461
+ flexDirection: "column",
21462
+ gap: "0.3vw"
21463
+ }, children: [
21464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.35vw" }, children: [
21465
+ /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", width: "0.75vw", height: "0.75vw", fill: "none", stroke: "#2154ef", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }),
21466
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#2154ef", fontSize: "0.62vw", fontWeight: 700, letterSpacing: "0.12em", textTransform: "uppercase" }, children: t2("Legal Notice") })
21467
+ ] }),
21468
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.58vw", color: "var(--ps-text-secondary)", lineHeight: 1.55 }, children: t2("Your image will be used to generate a virtual try-on preview showing how selected items may look and fit. Images are processed securely and are not stored after generation.") })
20884
21469
  ] })
20885
21470
  ] })
20886
21471
  ] }),
@@ -21869,6 +22454,7 @@ function PrimeStyleTryonInner({
21869
22454
  const bodyRef = reactExports.useRef(null);
21870
22455
  const modelPoseRef = reactExports.useRef(null);
21871
22456
  const [bodyLandmarks, setBodyLandmarks] = reactExports.useState(null);
22457
+ const [faceLandmarks, setFaceLandmarks] = reactExports.useState(null);
21872
22458
  const selectedFileRef = reactExports.useRef(null);
21873
22459
  reactExports.useEffect(() => {
21874
22460
  try {
@@ -22449,8 +23035,10 @@ function PrimeStyleTryonInner({
22449
23035
  setView("size-result");
22450
23036
  const measurementType = detectMeasurementType(productTitle);
22451
23037
  if (measurementType === "face" || measurementType === "head") {
23038
+ setFaceLandmarks(null);
22452
23039
  try {
22453
23040
  const faceResult = await detectFaceMeasurements(objUrl);
23041
+ if (faceResult) setFaceLandmarks(faceResult.landmarks);
22454
23042
  const facePayload = {
22455
23043
  product: { title: productTitle },
22456
23044
  sizeGuide: sizeGuide ?? { found: false },
@@ -23104,6 +23692,8 @@ function PrimeStyleTryonInner({
23104
23692
  handleTryOnSubmit,
23105
23693
  tryOnProcessing,
23106
23694
  bodyLandmarks,
23695
+ faceLandmarks,
23696
+ measurementType: detectMeasurementType(productTitle),
23107
23697
  activeSection,
23108
23698
  setActiveSection,
23109
23699
  onResetTryOn: () => {