@primestyleai/tryon 5.8.39 → 5.8.40

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.
@@ -3668,6 +3668,101 @@ const STYLES = `
3668
3668
  }
3669
3669
  .ps-pm-preview-remove:hover { background: #FFFFFF; }
3670
3670
 
3671
+ /* ── Mobile age-gate overlay ── */
3672
+ .ps-pm-preview-blurred {
3673
+ filter: blur(6px) saturate(0.7);
3674
+ pointer-events: none;
3675
+ user-select: none;
3676
+ }
3677
+ .ps-pm-age-gate {
3678
+ position: absolute; inset: 0;
3679
+ display: flex; align-items: center; justify-content: center;
3680
+ padding: max(16px, 4vw);
3681
+ background: rgba(255, 255, 255, 0.55);
3682
+ backdrop-filter: blur(8px);
3683
+ -webkit-backdrop-filter: blur(8px);
3684
+ z-index: 2;
3685
+ animation: ps-pm-age-gate-in 0.28s ease-out both;
3686
+ }
3687
+ @keyframes ps-pm-age-gate-in {
3688
+ 0% { opacity: 0; transform: scale(0.97); }
3689
+ 100% { opacity: 1; transform: scale(1); }
3690
+ }
3691
+ .ps-pm-age-gate-card {
3692
+ width: 100%; max-width: max(280px, 82vw);
3693
+ padding: max(18px, 4.6vw) max(16px, 4.2vw);
3694
+ background: #FFFFFF;
3695
+ border: 1px solid var(--ps-border-subtle);
3696
+ border-radius: max(12px, 3vw);
3697
+ box-shadow: 0 20px 40px -12px rgba(17, 24, 39, 0.25),
3698
+ 0 8px 16px -8px rgba(17, 24, 39, 0.15);
3699
+ display: flex; flex-direction: column;
3700
+ align-items: center; text-align: center;
3701
+ gap: max(8px, 2vw);
3702
+ }
3703
+ .ps-pm-age-gate-eyebrow {
3704
+ font-size: max(10px, 2.6vw); font-weight: 700;
3705
+ letter-spacing: 0.14em; text-transform: uppercase;
3706
+ color: var(--ps-accent);
3707
+ }
3708
+ .ps-pm-age-gate-eyebrow-blocked { color: #C02626; }
3709
+ .ps-pm-age-gate-question {
3710
+ font-size: max(14px, 3.8vw); font-weight: 600;
3711
+ line-height: 1.35; color: var(--ps-text-primary); margin: 0;
3712
+ }
3713
+ .ps-pm-age-gate-actions {
3714
+ display: flex; flex-direction: column; gap: max(8px, 2vw);
3715
+ width: 100%; margin-top: max(4px, 1vw);
3716
+ }
3717
+ .ps-pm-age-gate-btn {
3718
+ width: 100%;
3719
+ padding: max(11px, 2.9vw) max(14px, 3.6vw);
3720
+ border-radius: 999px;
3721
+ font-family: inherit;
3722
+ font-size: max(12px, 3.2vw); font-weight: 700;
3723
+ letter-spacing: 0.02em;
3724
+ cursor: pointer;
3725
+ transition: background 0.18s, border-color 0.18s, color 0.18s;
3726
+ }
3727
+ .ps-pm-age-gate-btn-primary {
3728
+ background: var(--ps-accent);
3729
+ color: #FFFFFF;
3730
+ border: 1.5px solid var(--ps-accent);
3731
+ }
3732
+ .ps-pm-age-gate-btn-secondary {
3733
+ background: transparent;
3734
+ color: var(--ps-text-primary);
3735
+ border: 1.5px solid var(--ps-border-color);
3736
+ }
3737
+ .ps-pm-age-gate-btn-secondary:active {
3738
+ background: var(--ps-bg-secondary);
3739
+ }
3740
+
3741
+ /* ── Mobile legal notice ── */
3742
+ .ps-pm-legal-notice {
3743
+ margin-top: max(10px, 2.6vw);
3744
+ background: rgba(33, 84, 239, 0.04);
3745
+ border: 1px solid rgba(33, 84, 239, 0.16);
3746
+ border-radius: max(10px, 2.6vw);
3747
+ padding: max(10px, 2.6vw) max(12px, 3.1vw);
3748
+ display: flex; flex-direction: column;
3749
+ gap: max(4px, 1vw);
3750
+ }
3751
+ .ps-pm-legal-notice-head {
3752
+ display: flex; align-items: center;
3753
+ gap: max(6px, 1.5vw);
3754
+ font-size: max(10px, 2.6vw); font-weight: 700;
3755
+ letter-spacing: 0.12em; text-transform: uppercase;
3756
+ color: var(--ps-accent);
3757
+ }
3758
+ .ps-pm-legal-notice-head svg { width: max(13px, 3.4vw); height: max(13px, 3.4vw); }
3759
+ .ps-pm-legal-notice-body {
3760
+ margin: 0;
3761
+ font-size: max(11px, 2.9vw);
3762
+ line-height: 1.5;
3763
+ color: var(--ps-text-secondary);
3764
+ }
3765
+
3671
3766
  /* Checklist for accuracy card */
3672
3767
  .ps-pm-checklist {
3673
3768
  display: flex; gap: max(12px, 3.1vw);
@@ -5529,6 +5624,127 @@ const STYLES = `
5529
5624
  transition: background 0.18s;
5530
5625
  }
5531
5626
  .ps-cpw-photo-retake:hover { background: rgba(33, 84, 239, 0.08); }
5627
+
5628
+ /* ── Age-gate overlay on the dropzone ──
5629
+ Dropzone stays visible but blurred; overlay shows a premium card
5630
+ with the 18+ confirmation question and two pill buttons. */
5631
+ .ps-cpw-dropzone-wrap {
5632
+ position: relative;
5633
+ flex: 1; min-height: 0;
5634
+ width: 100%; box-sizing: border-box;
5635
+ display: flex; flex-direction: column;
5636
+ }
5637
+ .ps-cpw-dropzone-blurred {
5638
+ filter: blur(6px) saturate(0.7);
5639
+ pointer-events: none;
5640
+ user-select: none;
5641
+ }
5642
+ .ps-cpw-age-gate {
5643
+ position: absolute; inset: 0;
5644
+ display: flex; align-items: center; justify-content: center;
5645
+ padding: clamp(12px, 1vw, 24px);
5646
+ border-radius: clamp(10px, 0.75vw, 16px);
5647
+ background: rgba(255, 255, 255, 0.55);
5648
+ backdrop-filter: blur(8px);
5649
+ -webkit-backdrop-filter: blur(8px);
5650
+ z-index: 2;
5651
+ animation: ps-cpw-age-gate-in 0.28s ease-out both;
5652
+ }
5653
+ @keyframes ps-cpw-age-gate-in {
5654
+ 0% { opacity: 0; transform: scale(0.97); }
5655
+ 100% { opacity: 1; transform: scale(1); }
5656
+ }
5657
+ .ps-cpw-age-gate-card {
5658
+ width: 100%; max-width: clamp(240px, 24vw, 420px);
5659
+ padding: clamp(16px, 1.4vw, 28px) clamp(18px, 1.6vw, 32px);
5660
+ background: #FFFFFF;
5661
+ border: 1px solid var(--ps-border-subtle);
5662
+ border-radius: clamp(10px, 0.9vw, 18px);
5663
+ box-shadow: 0 20px 40px -12px rgba(17, 24, 39, 0.25),
5664
+ 0 8px 16px -8px rgba(17, 24, 39, 0.15);
5665
+ display: flex; flex-direction: column;
5666
+ align-items: center; text-align: center;
5667
+ gap: clamp(8px, 0.7vw, 14px);
5668
+ }
5669
+ .ps-cpw-age-gate-eyebrow {
5670
+ font-size: clamp(9px, 0.62vw, 11px);
5671
+ font-weight: 700;
5672
+ letter-spacing: 0.18em;
5673
+ text-transform: uppercase;
5674
+ color: var(--ps-accent);
5675
+ }
5676
+ .ps-cpw-age-gate-eyebrow-blocked { color: #C02626; }
5677
+ .ps-cpw-age-gate-question {
5678
+ font-size: clamp(13px, 0.95vw, 18px);
5679
+ font-weight: 600;
5680
+ line-height: 1.35;
5681
+ color: var(--ps-text-primary);
5682
+ margin: 0;
5683
+ }
5684
+ .ps-cpw-age-gate-actions {
5685
+ display: flex; gap: clamp(8px, 0.65vw, 14px);
5686
+ width: 100%;
5687
+ margin-top: clamp(4px, 0.35vw, 8px);
5688
+ }
5689
+ .ps-cpw-age-gate-btn {
5690
+ flex: 1;
5691
+ padding: clamp(9px, 0.75vw, 14px) clamp(12px, 1vw, 18px);
5692
+ border-radius: 999px;
5693
+ font-family: inherit;
5694
+ font-size: clamp(11px, 0.78vw, 14px);
5695
+ font-weight: 700;
5696
+ letter-spacing: 0.02em;
5697
+ cursor: pointer;
5698
+ transition: transform 0.18s, background 0.18s, border-color 0.18s, color 0.18s;
5699
+ }
5700
+ .ps-cpw-age-gate-btn:hover { transform: translateY(-1px); }
5701
+ .ps-cpw-age-gate-btn-primary {
5702
+ background: var(--ps-accent);
5703
+ color: #FFFFFF;
5704
+ border: 1.5px solid var(--ps-accent);
5705
+ }
5706
+ .ps-cpw-age-gate-btn-primary:hover { background: color-mix(in srgb, var(--ps-accent) 88%, #000); }
5707
+ .ps-cpw-age-gate-btn-secondary {
5708
+ background: transparent;
5709
+ color: var(--ps-text-primary);
5710
+ border: 1.5px solid var(--ps-border-color);
5711
+ }
5712
+ .ps-cpw-age-gate-btn-secondary:hover {
5713
+ background: var(--ps-bg-secondary);
5714
+ border-color: var(--ps-text-muted);
5715
+ }
5716
+ .ps-cpw-age-gate-card-blocked { border-color: rgba(192, 38, 38, 0.35); }
5717
+
5718
+ /* ── Legal notice card on the right column ──
5719
+ Soft neutral card with a small shield icon; matches photo-guide width. */
5720
+ .ps-cpw-legal-notice {
5721
+ background: rgba(33, 84, 239, 0.04);
5722
+ border: 1px solid rgba(33, 84, 239, 0.16);
5723
+ border-radius: clamp(10px, 0.75vw, 16px);
5724
+ padding: clamp(10px, 0.9vw, 18px) clamp(12px, 1vw, 20px);
5725
+ display: flex; flex-direction: column;
5726
+ gap: clamp(5px, 0.45vw, 10px);
5727
+ }
5728
+ .ps-cpw-legal-notice-head {
5729
+ display: flex; align-items: center;
5730
+ gap: clamp(6px, 0.5vw, 10px);
5731
+ font-size: clamp(9px, 0.62vw, 11px);
5732
+ font-weight: 700;
5733
+ letter-spacing: 0.14em;
5734
+ text-transform: uppercase;
5735
+ color: var(--ps-accent);
5736
+ }
5737
+ .ps-cpw-legal-notice-head svg {
5738
+ width: clamp(12px, 0.85vw, 15px);
5739
+ height: clamp(12px, 0.85vw, 15px);
5740
+ }
5741
+ .ps-cpw-legal-notice-body {
5742
+ margin: 0;
5743
+ font-size: clamp(10px, 0.7vw, 12.5px);
5744
+ line-height: 1.5;
5745
+ color: var(--ps-text-secondary);
5746
+ }
5747
+
5532
5748
  .ps-cpw-hint {
5533
5749
  font-size: clamp(10px, 0.72vw, 13px);
5534
5750
  line-height: 1.6;
@@ -7446,6 +7662,102 @@ const SKELETON_CONNECTIONS = [
7446
7662
  ["rightHip", "rightKnee"],
7447
7663
  ["rightKnee", "rightAnkle"]
7448
7664
  ];
7665
+ function FaceOverlay({
7666
+ landmarks,
7667
+ imgWidth,
7668
+ imgHeight
7669
+ }) {
7670
+ const W = imgWidth;
7671
+ const H = imgHeight;
7672
+ const pts = [
7673
+ { key: "forehead", p: landmarks.forehead },
7674
+ { key: "chin", p: landmarks.chin },
7675
+ { key: "noseTip", p: landmarks.noseTip },
7676
+ { key: "noseBridge", p: landmarks.noseBridge },
7677
+ { key: "leftInnerEye", p: landmarks.leftInnerEye },
7678
+ { key: "rightInnerEye", p: landmarks.rightInnerEye },
7679
+ { key: "leftOuterEye", p: landmarks.leftOuterEye },
7680
+ { key: "rightOuterEye", p: landmarks.rightOuterEye },
7681
+ { key: "leftTragus", p: landmarks.leftTragus },
7682
+ { key: "rightTragus", p: landmarks.rightTragus },
7683
+ { key: "leftMouth", p: landmarks.leftMouth },
7684
+ { key: "rightMouth", p: landmarks.rightMouth }
7685
+ ];
7686
+ const connections = [
7687
+ // Face axis
7688
+ [landmarks.forehead, landmarks.noseBridge],
7689
+ [landmarks.noseBridge, landmarks.noseTip],
7690
+ [landmarks.noseTip, landmarks.chin],
7691
+ // Horizontal eye line
7692
+ [landmarks.leftOuterEye, landmarks.leftInnerEye],
7693
+ [landmarks.leftInnerEye, landmarks.rightInnerEye],
7694
+ [landmarks.rightInnerEye, landmarks.rightOuterEye],
7695
+ // Ears
7696
+ [landmarks.leftTragus, landmarks.leftOuterEye],
7697
+ [landmarks.rightOuterEye, landmarks.rightTragus],
7698
+ // Mouth line
7699
+ [landmarks.leftMouth, landmarks.rightMouth]
7700
+ ];
7701
+ return /* @__PURE__ */ jsxs("svg", { className: "ps-tryon-pose-overlay", viewBox: `0 0 ${W} ${H}`, preserveAspectRatio: "xMidYMid meet", children: [
7702
+ connections.map(([a, b], i) => /* @__PURE__ */ jsx(
7703
+ "line",
7704
+ {
7705
+ x1: a.x * W,
7706
+ y1: a.y * H,
7707
+ x2: b.x * W,
7708
+ y2: b.y * H,
7709
+ stroke: "rgba(100,210,255,0.55)",
7710
+ strokeWidth: "3",
7711
+ strokeLinecap: "round",
7712
+ opacity: "0",
7713
+ style: { animation: `ps-pose-fade 0.4s ease ${i * 0.05}s forwards` }
7714
+ },
7715
+ `fl-${i}`
7716
+ )),
7717
+ [landmarks.leftIrisCenter, landmarks.rightIrisCenter].map((c, i) => {
7718
+ const ring = i === 0 ? landmarks.leftIrisRing : landmarks.rightIrisRing;
7719
+ const rx = ring?.length ? Math.abs((ring[0]?.x ?? c.x) - (ring[2]?.x ?? c.x)) * W / 2 : 6;
7720
+ return /* @__PURE__ */ jsx(
7721
+ "circle",
7722
+ {
7723
+ cx: c.x * W,
7724
+ cy: c.y * H,
7725
+ r: Math.max(6, rx),
7726
+ fill: "none",
7727
+ stroke: "rgba(255,230,120,0.95)",
7728
+ strokeWidth: "2.5",
7729
+ opacity: "0",
7730
+ style: { animation: `ps-pose-fade 0.3s ease ${0.3 + i * 0.1}s forwards` }
7731
+ },
7732
+ `iris-${i}`
7733
+ );
7734
+ }),
7735
+ pts.map(({ key, p }, i) => /* @__PURE__ */ jsxs("g", { children: [
7736
+ /* @__PURE__ */ jsx(
7737
+ "circle",
7738
+ {
7739
+ cx: p.x * W,
7740
+ cy: p.y * H,
7741
+ r: "11",
7742
+ fill: "rgba(100,210,255,0.22)",
7743
+ opacity: "0",
7744
+ style: { animation: `ps-pose-fade 0.3s ease ${i * 0.04}s forwards` }
7745
+ }
7746
+ ),
7747
+ /* @__PURE__ */ jsx(
7748
+ "circle",
7749
+ {
7750
+ cx: p.x * W,
7751
+ cy: p.y * H,
7752
+ r: "6",
7753
+ fill: "rgba(100,210,255,0.95)",
7754
+ opacity: "0",
7755
+ 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` }
7756
+ }
7757
+ )
7758
+ ] }, key))
7759
+ ] });
7760
+ }
7449
7761
  function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
7450
7762
  const W = imgWidth;
7451
7763
  const H = imgHeight;
@@ -8310,6 +8622,8 @@ function SizeResultView({
8310
8622
  handleTryOnSubmit,
8311
8623
  tryOnProcessing,
8312
8624
  bodyLandmarks,
8625
+ faceLandmarks = null,
8626
+ measurementType = "body",
8313
8627
  estimationDone = false,
8314
8628
  activeSection,
8315
8629
  setActiveSection,
@@ -8596,28 +8910,33 @@ function SizeResultView({
8596
8910
  onLoad: handleImgLoad
8597
8911
  }
8598
8912
  ),
8599
- bodyLandmarks && /* @__PURE__ */ jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h })
8913
+ measurementType === "face" || measurementType === "head" ? faceLandmarks && /* @__PURE__ */ jsx(FaceOverlay, { landmarks: faceLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h }) : bodyLandmarks && /* @__PURE__ */ jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h })
8600
8914
  ] }),
8601
- /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
8602
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${bodyLandmarks ? " ps-done" : " ps-active"}`, children: [
8603
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: bodyLandmarks ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8604
- /* @__PURE__ */ jsx("span", { children: t("Detecting body pose") })
8605
- ] }),
8606
- !sizingDone && /* @__PURE__ */ jsxs(Fragment, { children: [
8607
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : bodyLandmarks ? " ps-active" : ""}`, children: [
8608
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !bodyLandmarks ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
8609
- /* @__PURE__ */ jsx("span", { children: t("Analyzing your size") })
8915
+ (() => {
8916
+ const isFaceCategory = measurementType === "face" || measurementType === "head";
8917
+ const detectionDone = isFaceCategory ? !!faceLandmarks : !!bodyLandmarks;
8918
+ const detectLabel = isFaceCategory ? measurementType === "head" ? t("Detecting head") : t("Detecting face") : t("Detecting body pose");
8919
+ return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-right-col ps-tryon-snap-steps", children: [
8920
+ /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${detectionDone ? " ps-done" : " ps-active"}`, children: [
8921
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: detectionDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8922
+ /* @__PURE__ */ jsx("span", { children: detectLabel })
8610
8923
  ] }),
8611
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
8612
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8613
- /* @__PURE__ */ jsx("span", { children: t("Finding best fit for you") })
8924
+ !sizingDone && /* @__PURE__ */ jsxs(Fragment, { children: [
8925
+ /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : detectionDone ? " ps-active" : ""}`, children: [
8926
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !detectionDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) }),
8927
+ /* @__PURE__ */ jsx("span", { children: t("Analyzing your size") })
8928
+ ] }),
8929
+ /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
8930
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8931
+ /* @__PURE__ */ jsx("span", { children: t("Finding best fit for you") })
8932
+ ] })
8933
+ ] }),
8934
+ tryOnProcessing && /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
8935
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8936
+ /* @__PURE__ */ jsx("span", { children: t("Generating virtual try-on") })
8614
8937
  ] })
8615
- ] }),
8616
- tryOnProcessing && /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${tryOnDone ? " ps-done" : " ps-active"}`, children: [
8617
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: tryOnDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "✓" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
8618
- /* @__PURE__ */ jsx("span", { children: t("Generating virtual try-on") })
8619
- ] })
8620
- ] })
8938
+ ] });
8939
+ })()
8621
8940
  ] }),
8622
8941
  (allDone || sizingResult && !isSnapProcessing) && /* @__PURE__ */ jsxs(Fragment, { children: [
8623
8942
  isMultiSection ? activeSection ? (
@@ -9416,9 +9735,18 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t }
9416
9735
  const photoInputRef = useRef(null);
9417
9736
  const nameInputRef = useRef(null);
9418
9737
  const [nameShaking, setNameShaking] = useState(false);
9738
+ const [ageConfirmed, setAgeConfirmed] = useState(null);
9739
+ const openFilePicker = () => {
9740
+ if (ageConfirmed !== true) return;
9741
+ photoInputRef.current?.click();
9742
+ };
9419
9743
  const handlePhotoSelect = async (e) => {
9420
9744
  const file = e.target.files?.[0];
9421
9745
  if (!file) return;
9746
+ if (ageConfirmed !== true) {
9747
+ setError(t("Please confirm that the person in the photo is 18 or older before uploading."));
9748
+ return;
9749
+ }
9422
9750
  if (!file.type.startsWith("image/")) {
9423
9751
  setError(t("Please upload an image file"));
9424
9752
  return;
@@ -9999,18 +10327,71 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t }
9999
10327
  /* @__PURE__ */ jsx("div", { className: "ps-cpw-image-left", children: photoBase64 ? /* @__PURE__ */ jsxs("div", { className: "ps-cpw-photo-preview-frame", children: [
10000
10328
  /* @__PURE__ */ jsx("img", { src: photoBase64, alt: t("Profile photo"), className: "ps-cpw-photo-preview-img" }),
10001
10329
  /* @__PURE__ */ jsx("button", { type: "button", className: "ps-cpw-photo-remove", onClick: handleRemovePhoto, "aria-label": t("Remove photo"), children: "×" }),
10002
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-cpw-photo-retake-pill", onClick: () => photoInputRef.current?.click(), children: t("Retake") })
10003
- ] }) : /* @__PURE__ */ jsxs("button", { type: "button", className: "ps-cpw-dropzone", onClick: () => photoInputRef.current?.click(), disabled: photoUploading, children: [
10004
- /* @__PURE__ */ jsx("img", { src: photoUploadIllustrationImg, alt: "", "aria-hidden": "true", className: "ps-cpw-dropzone-silhouette" }),
10005
- /* @__PURE__ */ jsxs("div", { className: "ps-cpw-dropzone-content", children: [
10006
- /* @__PURE__ */ 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: [
10007
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
10008
- /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
10009
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
10010
- ] }),
10011
- /* @__PURE__ */ jsx("span", { className: "ps-cpw-dropzone-title", children: photoUploading ? t("Processing...") : t("Drop a photo or click to upload") }),
10012
- /* @__PURE__ */ jsx("span", { className: "ps-cpw-dropzone-hint", children: t("JPEG · PNG · WebP · up to 10MB") })
10013
- ] })
10330
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-cpw-photo-retake-pill", onClick: openFilePicker, children: t("Retake") })
10331
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "ps-cpw-dropzone-wrap", children: [
10332
+ /* @__PURE__ */ jsxs(
10333
+ "button",
10334
+ {
10335
+ type: "button",
10336
+ className: `ps-cpw-dropzone${ageConfirmed !== true ? " ps-cpw-dropzone-blurred" : ""}`,
10337
+ onClick: openFilePicker,
10338
+ disabled: photoUploading || ageConfirmed !== true,
10339
+ "aria-hidden": ageConfirmed !== true,
10340
+ tabIndex: ageConfirmed !== true ? -1 : 0,
10341
+ children: [
10342
+ /* @__PURE__ */ jsx("img", { src: photoUploadIllustrationImg, alt: "", "aria-hidden": "true", className: "ps-cpw-dropzone-silhouette" }),
10343
+ /* @__PURE__ */ jsxs("div", { className: "ps-cpw-dropzone-content", children: [
10344
+ /* @__PURE__ */ 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: [
10345
+ /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
10346
+ /* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
10347
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
10348
+ ] }),
10349
+ /* @__PURE__ */ jsx("span", { className: "ps-cpw-dropzone-title", children: photoUploading ? t("Processing...") : t("Drop a photo or click to upload") }),
10350
+ /* @__PURE__ */ jsx("span", { className: "ps-cpw-dropzone-hint", children: t("JPEG · PNG · WebP · up to 10MB") })
10351
+ ] })
10352
+ ]
10353
+ }
10354
+ ),
10355
+ ageConfirmed === null && /* @__PURE__ */ jsx("div", { className: "ps-cpw-age-gate", role: "dialog", "aria-labelledby": "ps-cpw-age-gate-q", children: /* @__PURE__ */ jsxs("div", { className: "ps-cpw-age-gate-card", children: [
10356
+ /* @__PURE__ */ jsx("div", { className: "ps-cpw-age-gate-eyebrow", children: t("AGE VERIFICATION") }),
10357
+ /* @__PURE__ */ jsx("div", { id: "ps-cpw-age-gate-q", className: "ps-cpw-age-gate-question", children: t("Is the person in this photo 18 years or older?") }),
10358
+ /* @__PURE__ */ jsxs("div", { className: "ps-cpw-age-gate-actions", children: [
10359
+ /* @__PURE__ */ jsx(
10360
+ "button",
10361
+ {
10362
+ type: "button",
10363
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-primary",
10364
+ onClick: () => {
10365
+ setAgeConfirmed(true);
10366
+ setError("");
10367
+ },
10368
+ children: t("Yes, 18 or older")
10369
+ }
10370
+ ),
10371
+ /* @__PURE__ */ jsx(
10372
+ "button",
10373
+ {
10374
+ type: "button",
10375
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-secondary",
10376
+ onClick: () => setAgeConfirmed(false),
10377
+ children: t("No, under 18")
10378
+ }
10379
+ )
10380
+ ] })
10381
+ ] }) }),
10382
+ ageConfirmed === false && /* @__PURE__ */ jsx("div", { className: "ps-cpw-age-gate", role: "alert", children: /* @__PURE__ */ jsxs("div", { className: "ps-cpw-age-gate-card ps-cpw-age-gate-card-blocked", children: [
10383
+ /* @__PURE__ */ jsx("div", { className: "ps-cpw-age-gate-eyebrow ps-cpw-age-gate-eyebrow-blocked", children: t("UPLOAD NOT ALLOWED") }),
10384
+ /* @__PURE__ */ jsx("div", { className: "ps-cpw-age-gate-question", children: t("For your safety, we cannot process photos of people under 18.") }),
10385
+ /* @__PURE__ */ jsx(
10386
+ "button",
10387
+ {
10388
+ type: "button",
10389
+ className: "ps-cpw-age-gate-btn ps-cpw-age-gate-btn-secondary",
10390
+ onClick: () => setAgeConfirmed(null),
10391
+ children: t("Go back")
10392
+ }
10393
+ )
10394
+ ] }) })
10014
10395
  ] }) }),
10015
10396
  /* @__PURE__ */ jsxs("div", { className: "ps-cpw-image-right", children: [
10016
10397
  /* @__PURE__ */ jsx("div", { className: "ps-bp-inline-fields ps-cpw-inline-fields", children: /* @__PURE__ */ jsxs("div", { className: "ps-bp-inline-row", children: [
@@ -10041,6 +10422,13 @@ function CreateProfileWizard({ onSave, onCancel, onPhotoPreview, onEstimate, t }
10041
10422
  ] })
10042
10423
  ] })
10043
10424
  ] }),
10425
+ /* @__PURE__ */ jsxs("div", { className: "ps-cpw-legal-notice", children: [
10426
+ /* @__PURE__ */ jsxs("div", { className: "ps-cpw-legal-notice-head", children: [
10427
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }),
10428
+ /* @__PURE__ */ jsx("span", { children: t("LEGAL NOTICE") })
10429
+ ] }),
10430
+ /* @__PURE__ */ jsx("p", { className: "ps-cpw-legal-notice-body", children: t("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.") })
10431
+ ] }),
10044
10432
  error && /* @__PURE__ */ jsx("div", { className: "ps-cpw-error", children: error })
10045
10433
  ] })
10046
10434
  ] }, "image-photo"),
@@ -10884,6 +11272,8 @@ function PhotoStepMobile({
10884
11272
  const isCloseUp = photoVariant === "close-up";
10885
11273
  const fileRef = useRef(null);
10886
11274
  const hasPhoto = !!photoPreview;
11275
+ const [ageConfirmed, setAgeConfirmed] = useState(null);
11276
+ const gated = !hasPhoto && ageConfirmed !== true;
10887
11277
  return /* @__PURE__ */ jsxs("div", { className: "ps-pm-root", children: [
10888
11278
  /* @__PURE__ */ jsxs("div", { className: "ps-pm-header", children: [
10889
11279
  /* @__PURE__ */ jsx("h2", { className: "ps-pm-title", children: isCloseUp ? t("Upload a face photo or selfie") : t("Review your photo") }),
@@ -10911,19 +11301,46 @@ function PhotoStepMobile({
10911
11301
  children: /* @__PURE__ */ jsx(CloseIconSm, {})
10912
11302
  }
10913
11303
  )
10914
- ] }) : /* @__PURE__ */ jsxs(
10915
- "button",
10916
- {
10917
- type: "button",
10918
- className: "ps-pm-preview-empty",
10919
- onClick: () => fileRef.current?.click(),
10920
- children: [
10921
- /* @__PURE__ */ jsx(UploadIconLg, {}),
10922
- /* @__PURE__ */ jsx("span", { className: "ps-pm-preview-empty-title", children: t("Tap to upload") }),
10923
- /* @__PURE__ */ jsx("span", { className: "ps-pm-preview-empty-hint", children: t("JPEG, PNG up to 10MB") })
10924
- ]
10925
- }
10926
- ) }),
11304
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
11305
+ /* @__PURE__ */ jsxs(
11306
+ "button",
11307
+ {
11308
+ type: "button",
11309
+ className: `ps-pm-preview-empty${gated ? " ps-pm-preview-blurred" : ""}`,
11310
+ onClick: () => {
11311
+ if (!gated) fileRef.current?.click();
11312
+ },
11313
+ disabled: gated,
11314
+ "aria-hidden": gated,
11315
+ tabIndex: gated ? -1 : 0,
11316
+ children: [
11317
+ /* @__PURE__ */ jsx(UploadIconLg, {}),
11318
+ /* @__PURE__ */ jsx("span", { className: "ps-pm-preview-empty-title", children: t("Tap to upload") }),
11319
+ /* @__PURE__ */ jsx("span", { className: "ps-pm-preview-empty-hint", children: t("JPEG, PNG up to 10MB") })
11320
+ ]
11321
+ }
11322
+ ),
11323
+ ageConfirmed === null && /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate", role: "dialog", children: /* @__PURE__ */ jsxs("div", { className: "ps-pm-age-gate-card", children: [
11324
+ /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate-eyebrow", children: t("AGE VERIFICATION") }),
11325
+ /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate-question", children: t("Is the person in this photo 18 years or older?") }),
11326
+ /* @__PURE__ */ jsxs("div", { className: "ps-pm-age-gate-actions", children: [
11327
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-primary", onClick: () => setAgeConfirmed(true), children: t("Yes, 18 or older") }),
11328
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => setAgeConfirmed(false), children: t("No, under 18") })
11329
+ ] })
11330
+ ] }) }),
11331
+ ageConfirmed === false && /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate", role: "alert", children: /* @__PURE__ */ jsxs("div", { className: "ps-pm-age-gate-card", children: [
11332
+ /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate-eyebrow ps-pm-age-gate-eyebrow-blocked", children: t("UPLOAD NOT ALLOWED") }),
11333
+ /* @__PURE__ */ jsx("div", { className: "ps-pm-age-gate-question", children: t("For your safety, we cannot process photos of people under 18.") }),
11334
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => setAgeConfirmed(null), children: t("Go back") })
11335
+ ] }) })
11336
+ ] }) }),
11337
+ /* @__PURE__ */ jsxs("div", { className: "ps-pm-legal-notice", children: [
11338
+ /* @__PURE__ */ jsxs("div", { className: "ps-pm-legal-notice-head", children: [
11339
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }),
11340
+ /* @__PURE__ */ jsx("span", { children: t("LEGAL NOTICE") })
11341
+ ] }),
11342
+ /* @__PURE__ */ jsx("p", { className: "ps-pm-legal-notice-body", children: t("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.") })
11343
+ ] }),
10927
11344
  /* @__PURE__ */ jsxs("div", { className: "ps-pm-checklist", children: [
10928
11345
  /* @__PURE__ */ jsx("div", { className: "ps-pm-checklist-icon", children: /* @__PURE__ */ jsx(InfoIcon, {}) }),
10929
11346
  /* @__PURE__ */ jsxs("div", { className: "ps-pm-checklist-body", children: [
@@ -12445,6 +12862,7 @@ function PrimeStyleTryonInner({
12445
12862
  const bodyRef = useRef(null);
12446
12863
  const modelPoseRef = useRef(null);
12447
12864
  const [bodyLandmarks, setBodyLandmarks] = useState(null);
12865
+ const [faceLandmarks, setFaceLandmarks] = useState(null);
12448
12866
  const selectedFileRef = useRef(null);
12449
12867
  useEffect(() => {
12450
12868
  try {
@@ -13025,8 +13443,10 @@ function PrimeStyleTryonInner({
13025
13443
  setView("size-result");
13026
13444
  const measurementType = detectMeasurementType(productTitle);
13027
13445
  if (measurementType === "face" || measurementType === "head") {
13446
+ setFaceLandmarks(null);
13028
13447
  try {
13029
13448
  const faceResult = await detectFaceMeasurements(objUrl);
13449
+ if (faceResult) setFaceLandmarks(faceResult.landmarks);
13030
13450
  const facePayload = {
13031
13451
  product: { title: productTitle },
13032
13452
  sizeGuide: sizeGuide ?? { found: false },
@@ -13680,6 +14100,8 @@ function PrimeStyleTryonInner({
13680
14100
  handleTryOnSubmit,
13681
14101
  tryOnProcessing,
13682
14102
  bodyLandmarks,
14103
+ faceLandmarks,
14104
+ measurementType: detectMeasurementType(productTitle),
13683
14105
  activeSection,
13684
14106
  setActiveSection,
13685
14107
  onResetTryOn: () => {