// ── Bespoke — 6-step guided commission flow ──────────────────────────

// Error boundary — catches render crashes inside any step and shows the
// error text rather than unmounting the whole app (black screen).
class BStepError extends React.Component {
  constructor(p) { super(p); this.state = { err: null }; }
  static getDerivedStateFromError(e) { return { err: e }; }
  render() {
    if (this.state.err) {
      return (
        <div style={{ padding: '60px 40px', color: 'var(--fg)' }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-3)', letterSpacing: '.14em', marginBottom: 12 }}>
            RENDER ERROR — please screenshot this and send to your developer
          </div>
          <pre style={{ fontSize: 12, whiteSpace: 'pre-wrap', color: '#c0392b' }}>
            {this.state.err.message}
          </pre>
        </div>
      );
    }
    return this.props.children;
  }
}

const BESPOKE_CATS = [
  { id: 'Biker',       label: 'Biker',       sub: 'Moto · asymmetric zip' },
  { id: 'Bomber',      label: 'Bomber',      sub: 'Ribbed cuffs · welt pockets' },
  { id: 'Aviator',     label: 'Aviator',     sub: 'B-3 · shearling collar' },
  { id: 'Café Racer',  label: 'Café Racer',  sub: 'Stand collar · clean lines' },
  { id: 'Coat',        label: 'Long Coat',   sub: 'Knee-length · notch lapel' },
  { id: 'Blazer',      label: 'Blazer',      sub: 'Tailored · single-button' },
  { id: 'Vest',        label: 'Vest',        sub: 'Sleeveless · zip front' },
  { id: 'Hooded',      label: 'Hooded',      sub: 'Attached hood · zip front' },
  { id: 'Countryside', label: 'Countryside', sub: 'Rugged · sherpa lined' },
  { id: 'Pants',       label: 'Pants',       sub: 'Leather trousers · tailored' },
  { id: 'Skirts',      label: 'Skirts',      sub: 'Leather skirt · fitted or flared' },
  { id: 'Sets',        label: 'Sets',        sub: 'Matching jacket + bottom' },
];

const BESPOKE_HIDES = [
  {
    id: 'cowhide',
    label: 'Full-grain cowhide',
    sub: '1.2–1.8mm · structured, ages best',
    img: 'assets/leather/full-grain-cowhide.jpg',
    feel: 'Firm & structured',
    weight: 'Heavy',
    aging: 'Develops rich patina over years',
    bestFor: 'Bikers, café racers, coats',
    desc: 'The top layer of the hide — unprocessed and unaltered. The most durable leather available. Starts firm, breaks in beautifully with wear, and deepens in colour and character for decades.',
  },
  {
    id: 'lamb',
    label: 'Top-grain lambskin',
    sub: '0.7–0.9mm · buttery, body-conscious',
    img: 'assets/leather/top-grain-lambskin.jpg',
    feel: 'Buttery & supple',
    weight: 'Lightweight',
    aging: 'Softens further, stays smooth',
    bestFor: 'Bombers, blazers, slim cuts',
    desc: 'Exceptionally soft from the first wear. Lambskin drapes with the body and moves like fabric. The most luxurious hand feel of any leather — chosen for close-fitting silhouettes.',
  },
  {
    id: 'shearling',
    label: 'Real shearling',
    sub: 'Toscana / merino · warmest, heaviest',
    img: 'assets/leather/shearling.jpg',
    feel: 'Plush & insulating',
    weight: 'Heavy',
    aging: 'Wool compresses, exterior weathers beautifully',
    bestFor: 'Aviators, countryside, cold climates',
    desc: 'Sheepskin with the wool still attached — leather exterior, natural fleece interior. Extraordinarily warm and unmistakably luxurious. The definitive choice for aviators and winter-weight cuts.',
  },
  {
    id: 'nubuck',
    label: 'Nubuck',
    sub: 'Velvety surface · patinas fastest',
    img: 'assets/leather/nubuck.jpg',
    feel: 'Velvety & matte',
    weight: 'Medium',
    aging: 'Grows character fastest of all types',
    bestFor: 'Countryside, bombers, vintage styles',
    desc: 'Full-grain leather buffed on the grain side to produce a matte, velvety surface. Available in a clean natural finish or pre-aged distressed finish — both acquire deeper patina with every outing. No two pieces age identically.',
  },
  {
    id: 'python-print',
    label: 'Python print',
    sub: 'Snake-embossed cowhide · exotic look, accessible',
    img: 'assets/leather/python-print.jpg',
    feel: 'Firm cowhide with elongated scale texture',
    weight: 'Medium',
    aging: 'Emboss holds; base ages like full-grain',
    bestFor: 'Café racers, bikers, bold statement styles',
    desc: 'Full-grain cowhide with a deep python-scale pattern hydraulically pressed into the surface. The narrow, interlocking scales create a more fluid, linear texture than alligator — striking from any angle, with the long-term durability of standard cowhide.',
  },
  {
    id: 'alligator-print',
    label: 'Alligator print',
    sub: 'Croc-embossed cowhide · exotic look, accessible',
    img: 'assets/leather/alligator-print.jpg',
    feel: 'Firm cowhide with raised scale texture',
    weight: 'Heavy',
    aging: 'Emboss holds; base ages like full-grain',
    bestFor: 'Bikers, café racers, bold statement styles',
    desc: 'Full-grain cowhide with a deep alligator-scale pattern hydraulically pressed into the surface. All the visual drama of exotic leather — the structured silhouette, the scale definition — with the durability and break-in of standard cowhide.',
  },
  {
    id: 'fleece',
    label: 'Fleece',
    sub: 'Synthetic · plush, vegan, lightweight',
    img: 'assets/liners/fleece.jpg',
    feel: 'Soft & plush',
    weight: 'Lightweight',
    aging: 'Stays soft; easy-care synthetic',
    bestFor: 'Casual layers, vegan builds, cozy warmth',
    desc: 'A plush synthetic fleece — soft, warm, and completely animal-free. A lightweight, easy-care alternative to leather for those who want cozy texture and a vegan build. No break-in, no special care.',
  },
];

const BESPOKE_LINERS = [
  { id:'viscose', label:'Viscose / Rayon', sub:'SEMI-SYNTHETIC · BREATHABLE', img:'assets/liners/viscose.jpg',
    desc:'A breathable, semi-synthetic viscose liner with a smooth, fluid drape that feels cool against the skin. It manages moisture better than pure synthetics and has a naturally luxurious hand — ideal for all-day wear.',
    feel:'Silky, fluid drape', breathability:'High', warmth:'Light', bestFor:'All-day wear' },
  { id:'satin', label:'Satin', sub:'GLOSSY · LOW-FRICTION', img:'assets/liners/satin.jpg',
    desc:'A sleek satin liner with a glossy finish and ultra-smooth feel that glides effortlessly over layers. Less breathable than natural fibres, but delivers that classic, polished interior of a premium leather jacket.',
    feel:'Slippery, high sheen', breathability:'Low', warmth:'Light–Mid', bestFor:'Dressy, easy on/off' },
  { id:'polyester', label:'Polyester', sub:'DURABLE · EASY-CARE', img:'assets/liners/polyester.jpg',
    desc:'A tough, wrinkle-resistant polyester liner built to handle everyday wear and tear. Highly durable and budget-friendly, though not as breathable as natural or semi-synthetic options.',
    feel:'Smooth, sturdy', breathability:'Low', warmth:'Mid', bestFor:'Heavy daily use' },
  { id:'cotton', label:'Cotton', sub:'NATURAL · BREATHABLE', img:'assets/liners/cotton.jpg',
    desc:'A lightweight cotton liner that breathes naturally and feels soft from day one. Ideal for mild climates and everyday wear, with a casual, matte interior that can show more wrinkling over time.',
    feel:'Soft, matte', breathability:'High', warmth:'Light', bestFor:'Warm climates' },
  { id:'silk', label:'Silk', sub:'LUXURY · INSULATING', img:'assets/liners/silk.jpg',
    desc:'A true silk liner for maximum luxury — feather-light, incredibly soft, and naturally insulating without bulk. Feels exceptional, but demands more delicate care than synthetic alternatives.',
    feel:'Feather-light, soft', breathability:'High', warmth:'Mid · insulating', bestFor:'Maximum luxury' },
  { id:'fleece', label:'Fleece', sub:'SYNTHETIC · PLUSH WARMTH', img:'assets/liners/fleece.jpg', add:0,
    desc:'A plush synthetic fleece liner built for serious cold, trapping heat close to the body for maximum warmth. Soft, easy-care, and cozy — our standard winter-ready interior at no extra charge.',
    feel:'Plush, high-loft', breathability:'Low', warmth:'Maximum', bestFor:'Deep winter' },
  { id:'shearling', label:'Genuine Shearling', sub:'REAL SHEEPSKIN · LUXE WARMTH', img:'assets/leather/shearling.jpg', add:150,
    desc:'Genuine shearling — natural sheepskin with the wool left on. Dense, breathable insulation that regulates temperature far better than synthetics, with an unmistakably luxurious hand. A premium upgrade for the coldest builds.',
    feel:'Dense, natural loft', breathability:'Mid', warmth:'Maximum', bestFor:'Luxury winter' },
  { id:'faux-fur', label:'Faux Fur', sub:'SYNTHETIC · PLUSH TWO-TONE WARMTH', img:'assets/liners/faux-fur.jpg', add:0,
    desc:'A plush, two-tone faux fur liner that mimics the look and warmth of genuine shearling without any animal materials. Dense and soft against the skin, with a rich tonal blend that adds depth to the interior — our vegan alternative to shearling, at no extra charge.',
    feel:'Dense, plush pile', breathability:'Low', warmth:'Maximum', bestFor:'Deep winter, vegan builds' },
  { id:'quilted', label:'Quilted', sub:'INSULATED · MOTO', img:'assets/liners/quilted.jpg',
    desc:'A classic quilted liner with a thin layer of insulation stitched between shell and lining. The quilting keeps the fill evenly distributed for reliable cold-weather performance in a slim, moto-friendly profile.',
    feel:'Structured, light loft', breathability:'Low–Mid', warmth:'Mid–High', bestFor:'Cold-weather moto' },
  { id:'mesh', label:'Mesh', sub:'HIGH-AIRFLOW · SUMMER', img:'assets/liners/mesh.jpg',
    desc:'A high-airflow mesh liner of perforated synthetic fabric that keeps air moving and stops the jacket sticking to your skin in the heat. The go-to for hot-weather and moto-focused builds where ventilation matters most.',
    feel:'Open, airy', breathability:'Maximum', warmth:'Minimal', bestFor:'Hot weather / over armour' },
  { id:'none', label:'No Lining', sub:'UNLINED · LIGHTEST', img:null, add:0,
    desc:'No lining at all — the leather left unlined for the lightest weight and most natural drape. The interior shows the back of the hide; warmth is minimal, so this suits mild weather or a deliberately raw, broken-in feel.',
    feel:'Bare, natural', breathability:'Maximum', warmth:'Minimal', bestFor:'Mild weather / raw feel' },
];

const BSTEPS = ['Style', 'Leather', 'Liner', 'Colour', 'Hardware', 'Size', 'Review'];

// ── Shared: colour accordion row ─────────────────────────────────────
function ColourAccordion({ groupKey, label, palette, activeColor, openKey, setOpenKey, onSelect }) {
  const isOpen = openKey === groupKey;
  const active = palette.find(c => c.name === activeColor);
  return (
    <div style={{ borderTop: '.5px solid var(--line-2)' }}>
      <button onClick={() => setOpenKey(isOpen ? null : groupKey)}
        style={{
          width: '100%', display: 'flex', alignItems: 'center',
          justifyContent: 'space-between', padding: '13px 0',
          background: 'transparent', border: 'none', cursor: 'pointer',
        }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          {active && (
            <span style={{
              width: 12, height: 12, borderRadius: '50%', background: active.hex,
              flexShrink: 0, outline: '1px solid var(--line-2)', outlineOffset: 1,
              display: 'inline-block',
            }} />
          )}
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.18em',
            textTransform: 'uppercase', color: active ? 'var(--fg)' : 'var(--fg-2)',
          }}>{label}</span>
        </div>
        <span style={{
          color: 'var(--fg-3)', fontSize: 14, lineHeight: 1,
          transform: isOpen ? 'rotate(180deg)' : 'none', transition: 'transform .2s',
        }}>∨</span>
      </button>
      {isOpen && (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, paddingBottom: 16 }}>
          {palette.map(({ name, hex }) => (
            <button key={name} title={name}
              onClick={() => { onSelect(name); setOpenKey(null); }}
              style={{
                width: 28, height: 28, borderRadius: '50%', background: hex,
                cursor: 'pointer', flexShrink: 0,
                border: activeColor === name ? '2px solid var(--fg)' : '2px solid transparent',
                outline: activeColor === name ? '1.5px solid var(--fg)' : '1.5px solid var(--line-2)',
                outlineOffset: 2, transition: 'outline .15s, border .15s',
              }} />
          ))}
        </div>
      )}
    </div>
  );
}

// ── Step shell ────────────────────────────────────────────────────────
function BStepShell({ n, title, sub, children, data, set, stepKey }) {
  return (
    <div className="bespoke-step container">
      <div className="mono" style={{ color: 'var(--fg-3)', marginBottom: 16 }}>
        Step {n} of {BSTEPS.length}
      </div>
      <h2 className="display" style={{ fontSize: 'clamp(40px, 6vw, 80px)', margin: 0, lineHeight: 1.02 }}>
        {title}
      </h2>
      {sub && (
        <p style={{
          fontSize: 14, lineHeight: 1.65, color: 'var(--fg-2)',
          maxWidth: 600, marginTop: 18, marginBottom: 40,
        }}>{sub}</p>
      )}
      <div style={{ marginTop: sub ? 0 : 32 }}>{children}</div>

      {/* Per-step customer notes */}
      {stepKey && set && (
        <div style={{ marginTop: 40, paddingTop: 24, borderTop: '.5px solid var(--line-2)', maxWidth: 720 }}>
          <div className="mono" style={{ fontSize: 10, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 8 }}>
            Notes for this step <span style={{ textTransform: 'none', letterSpacing: 0 }}>· optional</span>
          </div>
          <textarea rows={2}
            value={(data && data.notes && data.notes[stepKey]) || ''}
            onChange={e => set('notes', { ...((data && data.notes) || {}), [stepKey]: e.target.value })}
            placeholder="Anything we should know for this step — preferences, references, special requests…"
            style={{ width: '100%', background: 'color-mix(in srgb,var(--fg) 2%,transparent)', border: '.5px solid var(--line-2)', color: 'var(--fg)', padding: '12px 14px', fontFamily: 'var(--font-body)', fontSize: 13, lineHeight: 1.5, resize: 'vertical', outline: 'none', boxSizing: 'border-box' }} />
        </div>
      )}
    </div>
  );
}

// ── Step 1: Style ─────────────────────────────────────────────────────
function BStep1({ data, set }) {
  const [genderFilter, setGenderFilter] = React.useState(data.gender || null);

  const products = React.useMemo(() => {
    if (!data.category) return [];
    return (window.PRODUCTS || []).filter(p =>
      p.category === data.category &&
      (!genderFilter || p.gender === genderFilter) &&
      p.images && p.images.length > 0
    ).slice(0, 30);
  }, [data.category, genderFilter]);

  const changeGender = (g) => { setGenderFilter(g); set('gender', g); set('product', null); };

  return (
    <BStepShell n={1}
      title={<><em>Choose</em> your style.</>}
      sub="Pick the type of jacket, then select the specific piece you want us to build for you."
      data={data} set={set} stepKey="Style">

      {/* Gender filter */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 28 }}>
        {[null, 'Men', 'Women'].map(g => (
          <button key={g || 'all'} onClick={() => changeGender(g)} className="mono"
            style={{
              padding: '8px 20px',
              border: `.5px solid ${genderFilter === g ? 'var(--fg)' : 'var(--line-2)'}`,
              background: genderFilter === g ? 'color-mix(in srgb,var(--fg) 8%,transparent)' : 'transparent',
              color: genderFilter === g ? 'var(--fg)' : 'var(--fg-2)',
              fontSize: 10.5, letterSpacing: '.14em', cursor: 'pointer', transition: 'all .15s',
            }}>
            {g || 'All'}
          </button>
        ))}
      </div>

      {/* Category cards */}
      <div className="commission-grid" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))' }}>
        {BESPOKE_CATS.map(cat => (
          <button key={cat.id}
            onClick={() => { set('category', cat.id); set('product', null); }}
            className={`commission-card ${data.category === cat.id ? 'on' : ''}`}>
            <div className="commission-card-name display">{cat.label}</div>
            <div className="commission-card-sub mono">{cat.sub}</div>
          </button>
        ))}
      </div>

      {/* Product grid */}
      {data.category && (
        <div style={{ marginTop: 48 }}>
          <div style={{
            fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.18em',
            textTransform: 'uppercase', color: 'var(--fg-2)', marginBottom: 20,
          }}>
            {products.length} {data.category} {products.length === 1 ? 'jacket' : 'jackets'}
            {genderFilter ? ` · ${genderFilter}` : ''}
          </div>
          {products.length === 0 ? (
            <p className="mono" style={{ color: 'var(--fg-3)', padding: '32px 0' }}>
              No products found. Try a different gender filter.
            </p>
          ) : (
            <div className="bespoke-product-grid">
              {products.map(p => (
                <button key={p.id} onClick={() => set('product', p)}
                  className={`bespoke-product-card ${data.product?.id === p.id ? 'on' : ''}`}>
                  <div className="bespoke-product-img">
                    {p.images?.[0]
                      ? <img src={p.images[0]} alt={p.frenchName || p.name}
                          style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
                      : <div style={{ width: '100%', height: '100%', background: 'var(--surface)' }} />
                    }
                    {data.product?.id === p.id && (
                      <div style={{
                        position: 'absolute', inset: 0,
                        background: 'color-mix(in srgb,var(--fg) 14%,transparent)',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                      }}>
                        <svg width="22" height="22" viewBox="0 0 24 24" fill="none"
                          stroke="var(--bg)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                          <path d="M20 6L9 17l-5-5"/>
                        </svg>
                      </div>
                    )}
                  </div>
                  <div className="bespoke-product-label">
                    {p.frenchName || p.name}
                  </div>
                </button>
              ))}
            </div>
          )}
        </div>
      )}
    </BStepShell>
  );
}

// ── Step 2: Leather type ──────────────────────────────────────────────
function BStep2({ data, set }) {
  return (
    <BStepShell n={2}
      title={<><em>Choose</em> your leather.</>}
      sub="Every piece is cut from full-grade hide. Select the type that matches how you want it to wear and age over time."
      data={data} set={set} stepKey="Leather">

      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))',
        gap: 16,
      }}>
        {BESPOKE_HIDES.map(h => {
          const sel = data.hide === h.id;
          return (
            <div key={h.id}>
            <button onClick={() => set('hide', h.id)}
              style={{
                textAlign: 'left',
                border: sel ? '1.5px solid var(--fg)' : '.5px solid var(--line-2)',
                background: sel
                  ? 'color-mix(in srgb,var(--fg) 5%,transparent)'
                  : 'color-mix(in srgb,var(--fg) 2%,transparent)',
                padding: 0,
                cursor: 'pointer',
                transition: 'border-color .18s, background .18s',
                display: 'block',
                width: '100%',
              }}>

              {/* Inner grid wrapper — keeps display:grid off the <button> element (iOS Safari bug) */}
              <div style={{
                display: 'grid',
                gridTemplateColumns: '180px 1fr',
                overflow: 'hidden',
                position: 'relative',
              }}>

              {/* Jacket image — left column */}
              <div style={{
                position: 'relative',
                background: 'var(--surface)',
                overflow: 'hidden',
                minHeight: 220,
              }}>
                <img src={h.img} alt={h.label} style={{
                  position: 'absolute', inset: 0,
                  width: '100%', height: '100%',
                  objectFit: 'contain',
                  objectPosition: 'center',
                  display: 'block',
                  padding: '12px',
                  boxSizing: 'border-box',
                }} />
                {/* Selected checkmark */}
                {sel && (
                  <div style={{
                    position: 'absolute', top: 10, left: 10,
                    width: 26, height: 26, borderRadius: '50%',
                    background: 'var(--fg)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    zIndex: 2,
                  }}>
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="none"
                      stroke="var(--bg)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M20 6L9 17l-5-5"/>
                    </svg>
                  </div>
                )}
              </div>

              {/* Details — right column */}
              <div style={{
                padding: '20px 20px 20px 18px',
                borderLeft: '.5px solid var(--line-2)',
                display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
              }}>
                <div>
                  <div className="display" style={{ fontSize: 22, lineHeight: 1.05, marginBottom: 4 }}>
                    {h.label}
                  </div>
                  <div className="mono" style={{
                    fontSize: 9.5, color: 'var(--fg-3)',
                    letterSpacing: '.14em', marginBottom: 14,
                  }}>
                    {h.sub}
                  </div>
                  <p style={{
                    fontSize: 12.5, lineHeight: 1.7,
                    color: 'var(--fg-2)', margin: '0 0 16px',
                  }}>
                    {h.desc}
                  </p>
                </div>

                {/* Property table */}
                <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
                  {[
                    ['Feel',     h.feel],
                    ['Weight',   h.weight],
                    ['Aging',    h.aging],
                    ['Best for', h.bestFor],
                  ].map(([k, v]) => (
                    <div key={k} style={{
                      display: 'flex', justifyContent: 'space-between',
                      alignItems: 'baseline', gap: 8,
                      padding: '5px 0',
                      borderBottom: '.5px solid var(--line-2)',
                      fontFamily: 'var(--font-mono)', fontSize: 9.5,
                    }}>
                      <span style={{
                        color: 'var(--fg-3)', textTransform: 'uppercase',
                        letterSpacing: '.14em', flexShrink: 0,
                      }}>{k}</span>
                      <span style={{ color: 'var(--fg)', textAlign: 'right' }}>{v}</span>
                    </div>
                  ))}
                </div>
              </div>
              </div>{/* end inner grid wrapper */}
            </button>

            {/* Nubuck finish toggle — shown below card when selected */}
            {sel && h.id === 'nubuck' && (
              <div style={{
                marginTop: 2,
                padding: '11px 16px',
                border: '1.5px solid var(--fg)',
                borderTop: 'none',
                background: 'color-mix(in srgb,var(--fg) 3%,transparent)',
                display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 9.5,
                  letterSpacing: '.16em', textTransform: 'uppercase',
                  color: 'var(--fg-3)', flexShrink: 0,
                }}>Finish</span>
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 10,
                  color: data.nubuckFinish !== 'distressed' ? 'var(--fg)' : 'var(--fg-3)',
                  transition: 'color .2s',
                }}>Normal</span>
                {/* Toggle pill */}
                <div
                  onClick={() => set('nubuckFinish', data.nubuckFinish === 'distressed' ? 'normal' : 'distressed')}
                  style={{
                    width: 40, height: 22, borderRadius: 11, flexShrink: 0,
                    background: data.nubuckFinish === 'distressed' ? 'var(--fg)' : 'var(--line-2)',
                    position: 'relative', cursor: 'pointer', transition: 'background .2s',
                  }}>
                  <div style={{
                    position: 'absolute', top: 3,
                    left: data.nubuckFinish === 'distressed' ? 21 : 3,
                    width: 16, height: 16, borderRadius: '50%',
                    background: 'var(--bg)',
                    transition: 'left .2s',
                  }}/>
                </div>
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 10,
                  color: data.nubuckFinish === 'distressed' ? 'var(--fg)' : 'var(--fg-3)',
                  transition: 'color .2s',
                }}>Distressed</span>
              </div>
            )}
            </div>
          );
        })}
      </div>
    </BStepShell>
  );
}

// ── Step 3: Colour ────────────────────────────────────────────────────
// ── Step 3: Liner ─────────────────────────────────────────────────────
function BStepLiner({ data, set }) {
  const loPrice = useCurrency();
  return (
    <BStepShell n={3}
      title={<><em>Choose</em> your liner.</>}
      sub="The inside story. Pick the lining that sets the feel, breathability, and warmth of your jacket against the skin."
      data={data} set={set} stepKey="Liner">
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))', gap: 16 }}>
        {BESPOKE_LINERS.map(l => {
          const sel = data.liner === l.id;
          return (
            <button key={l.id} onClick={() => set('liner', l.id)}
              style={{ textAlign: 'left', border: sel ? '1.5px solid var(--fg)' : '.5px solid var(--line-2)',
                background: sel ? 'color-mix(in srgb,var(--fg) 5%,transparent)' : 'color-mix(in srgb,var(--fg) 2%,transparent)',
                padding: 0, cursor: 'pointer', transition: 'border-color .18s, background .18s', display: 'block', width: '100%' }}>
              <div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', overflow: 'hidden', position: 'relative' }}>
                <div style={{ position: 'relative', background: 'var(--surface)', overflow: 'hidden', minHeight: 220 }}>
                  {l.img ? (
                    <img src={l.img} alt={l.label} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center', display: 'block' }} />
                  ) : (
                    <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center', padding: 12 }}>
                      <span className="mono" style={{ fontSize: 10, letterSpacing: '.16em', color: 'var(--fg-3)', textTransform: 'uppercase' }}>No&nbsp;lining</span>
                    </div>
                  )}
                  {sel && (
                    <div style={{ position: 'absolute', top: 10, left: 10, width: 26, height: 26, borderRadius: '50%', background: 'var(--fg)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 2 }}>
                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--bg)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>
                    </div>
                  )}
                </div>
                <div style={{ padding: '20px 20px 20px 18px', borderLeft: '.5px solid var(--line-2)', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
                  <div>
                    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 8, marginBottom: 4 }}>
                      <div className="display" style={{ fontSize: 22, lineHeight: 1.05 }}>{l.label}</div>
                      <div className="mono" style={{ fontSize: 10.5, letterSpacing: '.08em', flexShrink: 0, color: l.add > 0 ? 'var(--fg)' : 'var(--fg-3)' }}>
                        {l.add > 0 ? '+ ' + loPrice(l.add) : 'Included'}
                      </div>
                    </div>
                    <div className="mono" style={{ fontSize: 9.5, color: 'var(--fg-3)', letterSpacing: '.14em', marginBottom: 14 }}>{l.sub}</div>
                    <p style={{ fontSize: 12.5, lineHeight: 1.7, color: 'var(--fg-2)', margin: '0 0 16px' }}>{l.desc}</p>
                  </div>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
                    {[['Feel', l.feel], ['Breathability', l.breathability], ['Warmth', l.warmth], ['Best for', l.bestFor]].map(([k, v]) => (
                      <div key={k} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8, padding: '5px 0', borderBottom: '.5px solid var(--line-2)', fontFamily: 'var(--font-mono)', fontSize: 9.5 }}>
                        <span style={{ color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '.14em', flexShrink: 0 }}>{k}</span>
                        <span style={{ color: 'var(--fg)', textAlign: 'right' }}>{v}</span>
                      </div>
                    ))}
                  </div>
                </div>
              </div>
            </button>
          );
        })}
      </div>
    </BStepShell>
  );
}

function BStep3({ data, set }) {
  const [primOpen, setPrimOpen] = React.useState(null);
  const [secOpen,  setSecOpen]  = React.useState(null);
  const NAT = window.NATURAL_COLORS || [];
  const DYE = window.DYED_COLORS    || [];

  return (
    <BStepShell n={4}
      title={<><em>Choose</em> your colour.</>}
      sub="Pick the main leather colour. The optional secondary colour is the colour used for the liner, collar, trim, and accent details."
      data={data} set={set} stepKey="Colour">

      {/* Primary */}
      <div style={{
        display: 'flex', justifyContent: 'space-between',
        fontFamily: 'var(--font-mono)', fontSize: 11,
        letterSpacing: '.18em', textTransform: 'uppercase',
        color: 'var(--fg-2)', marginBottom: 14,
      }}>
        <span>Primary colour</span>
        {data.primaryColor && <span style={{ color: 'var(--fg)' }}>{data.primaryColor}</span>}
      </div>

      <ColourAccordion groupKey="nat" label="Natural Leathers" palette={NAT}
        activeColor={data.primaryColor} openKey={primOpen} setOpenKey={setPrimOpen}
        onSelect={v => set('primaryColor', v)} />
      <ColourAccordion groupKey="dye" label="Dyed Leathers" palette={DYE}
        activeColor={data.primaryColor} openKey={primOpen} setOpenKey={setPrimOpen}
        onSelect={v => set('primaryColor', v)} />
      <div style={{ borderTop: '.5px solid var(--line-2)' }} />

      {/* Secondary */}
      <div style={{
        marginTop: 40, padding: '26px 24px 22px',
        border: '.5px solid var(--line-2)',
        background: 'color-mix(in srgb,var(--fg) 2%,transparent)',
      }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 10 }}>
          <div style={{
            fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.18em',
            textTransform: 'uppercase', color: 'var(--fg-2)',
          }}>Secondary accent</div>
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '.12em',
            textTransform: 'uppercase', color: 'var(--fg-3)',
            border: '.5px solid var(--line-2)', padding: '2px 8px',
          }}>optional</span>
          {data.secondaryColor && (
            <span style={{ marginLeft: 'auto', color: 'var(--fg)', fontFamily: 'var(--font-mono)', fontSize: 10 }}>
              {data.secondaryColor}
            </span>
          )}
        </div>
        <p style={{
          fontFamily: 'var(--font-mono)', fontSize: 10.5, lineHeight: 1.75,
          color: 'var(--fg-3)', maxWidth: 540, margin: '0 0 16px',
        }}>
          A second tone for accent surfaces — shearling or fur collar, collar trim, or contrast stitching.
        </p>

        <div style={{
          marginBottom: 16, padding: '12px 14px',
          border: '.5px solid var(--line-2)', borderLeft: '2px solid var(--gold, #c6a86b)',
          background: 'color-mix(in srgb,var(--fg) 3%,transparent)',
          fontFamily: 'var(--font-mono)', fontSize: 10.5, lineHeight: 1.7, color: 'var(--fg-2)',
        }}>
          <strong style={{ color: 'var(--fg)' }}>Tell us where it goes.</strong> In the <strong style={{ color: 'var(--fg)' }}>Notes</strong> box at the bottom of this step, specify exactly which surfaces this accent colour should cover — e.g. collar, cuffs, trim, contrast stitching, or lining. If left blank, we apply our best judgement.
        </div>

        <button onClick={() => set('secondaryColor', null)} className="mono"
          style={{
            fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.16em',
            textTransform: 'uppercase', padding: '8px 16px', marginBottom: 16, cursor: 'pointer',
            border: !data.secondaryColor ? '1px solid var(--fg)' : '.5px solid var(--line-2)',
            color: !data.secondaryColor ? 'var(--fg)' : 'var(--fg-3)',
            background: !data.secondaryColor ? 'color-mix(in srgb,var(--fg) 6%,transparent)' : 'transparent',
            transition: 'color .15s, border .15s, background .15s',
          }}>
          None — no accent colour
        </button>

        <ColourAccordion groupKey="sec-nat" label="Natural Leathers" palette={NAT}
          activeColor={data.secondaryColor} openKey={secOpen} setOpenKey={setSecOpen}
          onSelect={v => set('secondaryColor', v)} />
        <ColourAccordion groupKey="sec-dye" label="Dyed Leathers" palette={DYE}
          activeColor={data.secondaryColor} openKey={secOpen} setOpenKey={setSecOpen}
          onSelect={v => set('secondaryColor', v)} />
        <div style={{ borderTop: '.5px solid var(--line-2)' }} />

        {data.secondaryColor && (
          <button onClick={() => set('secondaryColor', null)} className="mono"
            style={{ color: 'var(--fg-3)', marginTop: 10, fontSize: 10, cursor: 'pointer' }}
            onMouseEnter={e => e.currentTarget.style.color = 'var(--fg)'}
            onMouseLeave={e => e.currentTarget.style.color = 'var(--fg-3)'}>
            Clear secondary ✕
          </button>
        )}
      </div>
    </BStepShell>
  );
}

// ── Step 4: Hardware ──────────────────────────────────────────────────
function BStep4({ data, set }) {
  const [primOpen, setPrimOpen] = React.useState(false);
  const [secOpen,  setSecOpen]  = React.useState(false);
  const HW = window.HARDWARE_COLORS || [];

  function HWAccordion({ label, activeColor, open, setOpen, onSelect, dimLabel }) {
    return (
      <>
        {dimLabel && (
          <div style={{
            fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.14em',
            textTransform: 'uppercase', color: 'var(--fg-3)', margin: '24px 0 8px',
            display: 'flex', justifyContent: 'space-between',
          }}>
            <span>{dimLabel}</span>
            {activeColor && <span style={{ color: 'var(--fg-2)' }}>{activeColor}</span>}
          </div>
        )}
        <div style={{ borderTop: '.5px solid var(--line-2)' }}>
          <button onClick={() => setOpen(o => !o)}
            style={{
              width: '100%', display: 'flex', alignItems: 'center',
              justifyContent: 'space-between', padding: '13px 0',
              background: 'transparent', border: 'none', cursor: 'pointer',
            }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              {activeColor && (() => {
                const hw = HW.find(h => h.name === activeColor);
                return hw
                  ? <span style={{
                      width: 12, height: 12, borderRadius: '50%', background: hw.hex,
                      flexShrink: 0, outline: '1px solid var(--line-2)', outlineOffset: 1,
                    }} />
                  : null;
              })()}
              <span style={{
                fontFamily: 'var(--font-mono)', fontSize: 10,
                letterSpacing: '.18em', textTransform: 'uppercase',
                color: activeColor ? 'var(--fg)' : 'var(--fg-2)',
              }}>{label}</span>
            </div>
            <span style={{
              color: 'var(--fg-3)', fontSize: 14, lineHeight: 1,
              transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .2s',
            }}>∨</span>
          </button>
          {open && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, paddingBottom: 16 }}>
              {HW.map(({ name, hex }) => (
                <button key={name} title={name}
                  onClick={() => { onSelect(name); setOpen(false); }}
                  style={{
                    width: 28, height: 28, borderRadius: '50%', background: hex,
                    cursor: 'pointer', flexShrink: 0,
                    border: activeColor === name ? '2px solid var(--fg)' : '2px solid transparent',
                    outline: activeColor === name ? '1.5px solid var(--fg)' : '1.5px solid var(--line-2)',
                    outlineOffset: 2, transition: 'outline .15s, border .15s',
                  }} />
              ))}
            </div>
          )}
        </div>
        <div style={{ borderTop: '.5px solid var(--line-2)' }} />
      </>
    );
  }

  return (
    <BStepShell n={5}
      title={<><em>Hardware</em> finish.</>}
      sub="Choose the finish for your zips, snaps, and buckles. A secondary finish is optional — for accent hardware like interior snaps."
      data={data} set={set} stepKey="Hardware">

      <div style={{
        display: 'flex', justifyContent: 'space-between',
        fontFamily: 'var(--font-mono)', fontSize: 11,
        letterSpacing: '.18em', textTransform: 'uppercase',
        color: 'var(--fg-2)', marginBottom: 14,
      }}>
        <span>Hardware</span>
        {data.hardwareColor && <span style={{ color: 'var(--fg)' }}>{data.hardwareColor}</span>}
      </div>

      <HWAccordion label="Finish options"
        activeColor={data.hardwareColor} open={primOpen} setOpen={setPrimOpen}
        onSelect={v => set('hardwareColor', v)} />

      <div style={{
        marginTop: 24, marginBottom: 4, padding: '12px 14px',
        border: '.5px solid var(--line-2)', borderLeft: '2px solid var(--gold, #c6a86b)',
        background: 'color-mix(in srgb,var(--fg) 3%,transparent)',
        fontFamily: 'var(--font-mono)', fontSize: 10.5, lineHeight: 1.7, color: 'var(--fg-2)',
      }}>
        <strong style={{ color: 'var(--fg)' }}>Specify your hardware.</strong> In the <strong style={{ color: 'var(--fg)' }}>Notes</strong> box at the bottom of this step, tell us which hardware this secondary finish applies to — e.g. zippers, buttons, snaps, buckles, or studs/spikes — plus any placement details. If left blank, we apply our best judgement.
      </div>

      <HWAccordion label="Finish options" dimLabel="Secondary finish"
        activeColor={data.secondaryHardwareColor} open={secOpen} setOpen={setSecOpen}
        onSelect={v => set('secondaryHardwareColor', v)} />

      <button onClick={() => set('secondaryHardwareColor', null)} className="mono"
        style={{
          fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '.16em',
          textTransform: 'uppercase', padding: '8px 16px', marginTop: 14, cursor: 'pointer',
          border: !data.secondaryHardwareColor ? '1px solid var(--fg)' : '.5px solid var(--line-2)',
          color: !data.secondaryHardwareColor ? 'var(--fg)' : 'var(--fg-3)',
          background: !data.secondaryHardwareColor ? 'color-mix(in srgb,var(--fg) 6%,transparent)' : 'transparent',
          transition: 'color .15s, border .15s, background .15s',
        }}>
        None — no second hardware finish
      </button>

      {data.secondaryHardwareColor && (
        <button onClick={() => set('secondaryHardwareColor', null)} className="mono"
          style={{ color: 'var(--fg-3)', marginTop: 10, fontSize: 10, cursor: 'pointer' }}
          onMouseEnter={e => e.currentTarget.style.color = 'var(--fg)'}
          onMouseLeave={e => e.currentTarget.style.color = 'var(--fg-3)'}>
          Clear secondary hardware ✕
        </button>
      )}
    </BStepShell>
  );
}

// ── Step 5: Measurements ──────────────────────────────────────────────
function BStep5({ data, set }) {
  const [unit, setUnit] = React.useState('in');
  const [bodyPart, setBodyPart] = React.useState('upper');
  const [fields, setFields] = React.useState(
    data.customFields && Object.keys(data.customFields).length
      ? data.customFields
      : { neck:'',chest:'',shoulders:'',sleeve:'',bicep:'',body:'',waist:'',hips:'',inseam:'',thigh:'',outseam:'',rise:'',height:'',weight:'',notes:'' }
  );
  const setF = (k, v) => setFields(f => ({ ...f, [k]: v }));

  React.useEffect(() => { set('size', 'Custom'); }, []);
  React.useEffect(() => { set('customFields', fields); }, [fields]);

  // ── saved measurement profiles ("Who are you ordering for?") ───────────
  const [profiles, setProfiles] = React.useState([]);
  const [selectedProfile, setSelectedProfile] = React.useState('');
  React.useEffect(() => {
    let active = true;
    (async () => {
      const sb = window.sb;
      if (!sb) return;
      try {
        const { data: sess } = await sb.auth.getSession();
        const token = sess && sess.session ? sess.session.access_token : null;
        if (!token) return;
        const r = await fetch('/api/measurement-profiles?a=list', { headers: { Authorization: 'Bearer ' + token } });
        const d = await r.json();
        if (active && d && d.ok) setProfiles(d.profiles || []);
      } catch { /* non-fatal — manual entry still works */ }
    })();
    return () => { active = false; };
  }, []);
  const applyProfile = (id) => {
    setSelectedProfile(id);
    if (!id) { set('orderedForName', ''); set('orderedForRelationship', ''); return; }
    const p = profiles.find(x => x.id === id);
    if (!p) return;
    setFields(f => ({ ...f, ...(p.measurements || {}) }));
    if (p.unit === 'in' || p.unit === 'cm') setUnit(p.unit);
    set('orderedForName', p.name || '');
    set('orderedForRelationship', p.relationship || '');
  };

  const inputStyle = {
    width: '100%', boxSizing: 'border-box', padding: '12px 14px',
    background: 'transparent', border: '.5px solid var(--line-2)',
    color: 'var(--fg)', fontFamily: 'var(--font-mono)', fontSize: 13, outline: 'none',
  };
  const labelStyle = {
    fontFamily: 'var(--font-mono)', fontSize: 9,
    letterSpacing: '.18em', textTransform: 'uppercase',
    color: 'var(--fg-3)', marginBottom: 6,
  };

  const FIELD_SETS = {
    upper: [
      { k:'neck',      l:'Neck',            i:'e.g. 15.5',   c:'e.g. 39'  },
      { k:'chest',     l:'Chest *',         i:'e.g. 40',     c:'e.g. 102' },
      { k:'shoulders', l:'Shoulders *',     i:'e.g. 17.5',   c:'e.g. 44'  },
      { k:'sleeve',    l:'Sleeve length *', i:'e.g. 25',     c:'e.g. 64'  },
      { k:'bicep',     l:'Bicep',           i:'e.g. 14',     c:'e.g. 36'  },
      { k:'body',      l:'Back length',     i:'e.g. 28',     c:'e.g. 71'  },
      { k:'height',    l:'Height',          i:"e.g. 5'11\"", c:'e.g. 180' },
      { k:'weight',    l:'Weight',          i:'e.g. 165 lbs',c:'e.g. 75 kg'},
    ],
    lower: [
      { k:'waist',     l:'Waist',           i:'e.g. 34',     c:'e.g. 86'  },
      { k:'hips',      l:'Hip / Seat',      i:'e.g. 38',     c:'e.g. 97'  },
      { k:'inseam',    l:'Inseam',          i:'e.g. 32',     c:'e.g. 81'  },
      { k:'thigh',     l:'Thigh',           i:'e.g. 22',     c:'e.g. 56'  },
      { k:'outseam',   l:'Outseam',         i:'e.g. 40',     c:'e.g. 102' },
      { k:'rise',      l:'Rise',            i:'e.g. 11',     c:'e.g. 28'  },
      { k:'height',    l:'Height',          i:"e.g. 5'11\"", c:'e.g. 180' },
      { k:'weight',    l:'Weight',          i:'e.g. 165 lbs',c:'e.g. 75 kg'},
    ],
  };

  // Plain-language how-to-measure descriptions (mirrors the Sizing page).
  const MEASURE_HELP = {
    neck:      'Around the base of the neck, where a shirt collar sits — leave one finger of room.',
    chest:     'Around the fullest part of your chest, just under the arms, tape parallel to the floor.',
    shoulders: 'From the bony tip of one shoulder straight across the back to the other shoulder tip.',
    sleeve:    'From the center back of the neck, over the shoulder point, down to the wrist bone.',
    bicep:     'Around the fullest part of the upper arm, relaxed at your side.',
    body:      'Back length — from the base of the neck straight down to your desired hem.',
    waist:     'Around your natural waist, about one inch above the navel — stand relaxed.',
    hips:      'Hip / seat — around the fullest part of your hips, 7 to 9 inches below the waist.',
    inseam:    'From the crotch seam straight down the inside of the leg to the ankle bone.',
    thigh:     'Around the fullest part of one upper thigh.',
    outseam:   'From the top of the waistband down the outside of the leg to the ankle.',
    rise:      'From the crotch seam up to the top of the waistband — how high the trousers sit on you.',
    height:    'Your full standing height, without shoes.',
    weight:    'Your body weight — lets us cross-check the overall fit.',
  };

  return (
    <BStepShell n={6}
      title={<><em>Your</em> measurements.</>}
      sub="Every piece is made to your exact dimensions. Fill in what you know; we'll follow up on anything missing."
      data={data} set={set} stepKey="Size">

      {/* ── Saved profile picker ────────────────────────────────────── */}
      {profiles.length > 0 && (
        <div style={{ marginBottom: 26, padding: '16px 18px', border: '.5px solid var(--line-2)', background: 'color-mix(in srgb,var(--fg) 2%,transparent)' }}>
          <div style={labelStyle}>Who are you ordering for?</div>
          <select value={selectedProfile} onChange={e => applyProfile(e.target.value)} style={{ ...inputStyle, marginTop: 6 }}>
            <option value="">— Enter measurements manually —</option>
            {profiles.map(p => (
              <option key={p.id} value={p.id}>{p.name}{p.relationship ? ` — ${p.relationship}` : ''}{p.is_default ? ' (Default)' : ''}</option>
            ))}
          </select>
          {selectedProfile && (
            <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 8 }}>
              Fields below are filled in from this profile — edit anything if it's changed.
            </div>
          )}
        </div>
      )}

      {/* ── How-to-measure diagrams ─────────────────────────────────── */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 14, marginBottom: 30 }}>

        {/* Upper body silhouette — Neck · Shoulders · Chest · Sleeve */}
        <div style={{ border: '.5px solid var(--line-2)', padding: '14px 10px 10px' }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 8, letterSpacing: '.16em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 10, textAlign: 'center' }}>
            Upper Body · Neck · Shoulders · Chest · Sleeve
          </div>
          <svg viewBox="0 0 200 222" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ width: '100%', height: 'auto', display: 'block' }}>
            {/* Vitruvian reference — inscribing circle + square + plumb line */}
            <circle cx="100" cy="118" r="94" stroke="currentColor" strokeWidth=".5" opacity=".09"/>
            <rect x="14" y="32" width="172" height="172" stroke="currentColor" strokeWidth=".5" opacity=".09"/>
            <line x1="100" y1="8" x2="100" y2="210" stroke="currentColor" strokeWidth=".4" strokeDasharray="2,3" opacity=".16"/>
            {/* Anatomical front figure */}
            <g fill="currentColor" fillOpacity=".1" stroke="currentColor" strokeWidth=".9" strokeOpacity=".5" strokeLinejoin="round">
              <path d="M100 11 C108 11 114 18 114 27 C114 35 110 41 105 44 L106 50 L94 50 L95 44 C90 41 86 35 86 27 C86 18 92 11 100 11 Z"/>
              <path d="M94 50 C90 53 83 55 75 58 C63 62 53 67 49 72 C44 79 40 91 37 105 C34 119 33 134 33 146 C33 150 38 151 40 147 C44 136 46 122 50 108 C52 100 56 92 60 86 C58 102 58 122 60 140 C61 150 63 158 66 164 L134 164 C137 158 139 150 140 140 C142 122 142 102 140 86 C144 92 148 100 150 108 C154 122 156 136 160 147 C162 151 167 150 167 146 C167 134 166 119 163 105 C160 91 156 79 151 72 C147 67 137 62 125 58 C117 55 110 53 106 50 C104 53 100 54 100 54 C100 54 96 53 94 50 Z"/>
              <ellipse cx="39" cy="168" rx="4" ry="6.5"/>
              <ellipse cx="161" cy="168" rx="4" ry="6.5"/>
              <path d="M100 56 L100 120" strokeWidth=".45" strokeOpacity=".28" fill="none"/>
              <path d="M70 80 C80 90 92 92 100 92 C108 92 120 90 130 80" strokeWidth=".45" strokeOpacity=".28" fill="none"/>
              <path d="M84 100 C91 109 100 110 100 110 C100 110 109 109 116 100" strokeWidth=".4" strokeOpacity=".22" fill="none"/>
            </g>
            {/* NECK */}
            <line x1="86" y1="51" x2="114" y2="51" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="86" y1="48" x2="86" y2="54" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="114" y1="48" x2="114" y2="54" stroke="currentColor" strokeWidth="1.2"/>
            <text x="100" y="44" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">NECK</text>
            {/* SHOULDERS */}
            <line x1="49" y1="70" x2="151" y2="70" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="49" y1="67" x2="49" y2="73" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="151" y1="67" x2="151" y2="73" stroke="currentColor" strokeWidth="1.2"/>
            <text x="100" y="64" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">SHOULDERS</text>
            {/* CHEST */}
            <line x1="56" y1="96" x2="144" y2="96" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="56" y1="93" x2="56" y2="99" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="144" y1="93" x2="144" y2="99" stroke="currentColor" strokeWidth="1.2"/>
            <text x="100" y="89" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">CHEST</text>
            {/* SLEEVE */}
            <line x1="178" y1="70" x2="178" y2="160" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="175" y1="70" x2="181" y2="70" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="175" y1="160" x2="181" y2="160" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="151" y1="70" x2="178" y2="70" stroke="currentColor" strokeWidth=".4" strokeDasharray="1.5,2.5" opacity=".3"/>
            <line x1="161" y1="160" x2="178" y2="160" stroke="currentColor" strokeWidth=".4" strokeDasharray="1.5,2.5" opacity=".3"/>
            <text transform="translate(190,115) rotate(-90)" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">SLEEVE</text>
            <text x="100" y="216" textAnchor="middle" fontSize="7.5" fill="currentColor" fontFamily="sans-serif" opacity=".38">Tape around the fullest part · seam to wrist</text>
          </svg>
        </div>

        {/* Lower body silhouette — Waist · Hips · Inseam · Length */}
        <div style={{ border: '.5px solid var(--line-2)', padding: '14px 10px 10px' }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 8, letterSpacing: '.16em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 10, textAlign: 'center' }}>
            Lower Body · Waist · Hips · Rise · Inseam
          </div>
          <svg viewBox="0 0 200 222" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ width: '100%', height: 'auto', display: 'block' }}>
            {/* Vitruvian reference — inscribing circle + square + plumb line */}
            <circle cx="100" cy="114" r="94" stroke="currentColor" strokeWidth=".5" opacity=".09"/>
            <rect x="14" y="28" width="172" height="172" stroke="currentColor" strokeWidth=".5" opacity=".09"/>
            {/* Anatomical lower figure — pelvis + legs */}
            <g fill="currentColor" fillOpacity=".1" stroke="currentColor" strokeWidth=".9" strokeOpacity=".5" strokeLinejoin="round">
              <path d="M70 20 C66 40 64 56 64 70 C64 82 68 92 76 100 C68 116 64 132 66 150 L72 200 L78 212 L92 212 C95 180 97 158 99 150 C100 145 100 144 101 144 C102 144 102 145 103 150 C105 158 107 180 110 212 L124 212 L130 200 L136 150 C138 132 134 116 126 100 C134 92 138 82 138 70 C138 56 136 40 132 20 Z"/>
              <path d="M80 160 C86 164 92 164 96 160 M106 160 C110 164 116 164 122 160" strokeWidth=".4" strokeOpacity=".2" fill="none"/>
            </g>
            {/* WAIST */}
            <line x1="66" y1="60" x2="134" y2="60" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="66" y1="57" x2="66" y2="63" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="134" y1="57" x2="134" y2="63" stroke="currentColor" strokeWidth="1.2"/>
            <text x="101" y="53" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">WAIST</text>
            {/* HIPS */}
            <line x1="62" y1="98" x2="92" y2="98" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="108" y1="98" x2="138" y2="98" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="62" y1="95" x2="62" y2="101" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="138" y1="95" x2="138" y2="101" stroke="currentColor" strokeWidth="1.2"/>
            <text x="77" y="91" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">HIPS</text>
            {/* RISE — front crotch up to top of waistband */}
            <line x1="100" y1="60" x2="100" y2="140" stroke="currentColor" strokeWidth="1" strokeDasharray="3,2.5"/>
            <line x1="97" y1="60" x2="103" y2="60" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="97" y1="140" x2="103" y2="140" stroke="currentColor" strokeWidth="1.2"/>
            <text transform="translate(116,102) rotate(-90)" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".82">RISE</text>
            {/* INSEAM — inner leg */}
            <line x1="150" y1="142" x2="150" y2="208" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="147" y1="142" x2="153" y2="142" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="147" y1="208" x2="153" y2="208" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="103" y1="142" x2="150" y2="142" stroke="currentColor" strokeWidth=".4" strokeDasharray="1.5,2.5" opacity=".3"/>
            <text transform="translate(162,175) rotate(-90)" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">INSEAM</text>
            {/* OUTSEAM — waistband down the side */}
            <line x1="32" y1="60" x2="32" y2="208" stroke="currentColor" strokeWidth=".8" strokeDasharray="3,2.5"/>
            <line x1="29" y1="60" x2="35" y2="60" stroke="currentColor" strokeWidth="1.2"/>
            <line x1="29" y1="208" x2="35" y2="208" stroke="currentColor" strokeWidth="1.2"/>
            <text transform="translate(22,134) rotate(-90)" textAnchor="middle" fontSize="8" fill="currentColor" fontFamily="monospace" letterSpacing=".5" opacity=".72">OUTSEAM</text>
            <text x="100" y="220" textAnchor="middle" fontSize="7.5" fill="currentColor" fontFamily="sans-serif" opacity=".38">Around at the fullest · crotch up = rise · seam down = inseam</text>
          </svg>
        </div>
      </div>

      {/* ── Upper / Lower body toggle ───────────────────────────────── */}
      <div style={{ display: 'flex', border: '.5px solid var(--line-2)', marginBottom: 18 }}>
        {[['upper', 'Upper body'], ['lower', 'Lower body']].map(([v, lbl]) => (
          <button key={v} onClick={() => setBodyPart(v)} style={{
            flex: 1, padding: '11px 0',
            background: bodyPart === v ? 'var(--fg)' : 'transparent',
            color: bodyPart === v ? 'var(--bg)' : 'var(--fg-2)',
            border: 'none', cursor: 'pointer',
            fontFamily: 'var(--font-mono)', fontSize: 10,
            letterSpacing: '.2em', textTransform: 'uppercase', transition: 'all .15s',
          }}>{lbl}</button>
        ))}
      </div>

      {/* ── Unit toggle + required note ─────────────────────────────── */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '.22em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>
          {bodyPart === 'upper'
            ? 'Chest, shoulders & sleeve required · others optional'
            : 'Lower-body measurements optional · fill what you know'}
        </div>
        <div style={{ display: 'flex', border: '.5px solid var(--line-2)', flexShrink: 0, marginLeft: 16 }}>
          {['in', 'cm'].map(u => (
            <button key={u} onClick={() => setUnit(u)} style={{
              padding: '5px 14px',
              background: unit === u ? 'var(--fg)' : 'transparent',
              color: unit === u ? 'var(--bg)' : 'var(--fg-2)',
              border: 'none', cursor: 'pointer',
              fontFamily: 'var(--font-mono)', fontSize: 9,
              letterSpacing: '.18em', textTransform: 'uppercase',
              transition: 'all .15s',
            }}>{u}</button>
          ))}
        </div>
      </div>

      {/* ── Measurement fields ──────────────────────────────────────── */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        {FIELD_SETS[bodyPart].map(({ k, l, i, c }) => (
          <div key={k}>
            <div style={labelStyle}>{l}</div>
            <input type="text" value={fields[k] || ''} onChange={e => setF(k, e.target.value)}
              placeholder={unit === 'cm' ? c : i}
              style={inputStyle}
              onFocus={e => e.target.style.borderColor = 'var(--fg)'}
              onBlur={e => e.target.style.borderColor = 'var(--line-2)'} />
          </div>
        ))}
      </div>

      {/* ── How to measure (descriptions for the fields above) ──────────── */}
      <div style={{ marginTop: 18, padding: '16px 18px', border: '.5px solid var(--line-2)', background: 'color-mix(in srgb,var(--fg) 2%,transparent)' }}>
        <div style={{ ...labelStyle, marginBottom: 10 }}>How to measure</div>
        {FIELD_SETS[bodyPart].map(({ k, l }) => MEASURE_HELP[k] ? (
          <div key={k} style={{ fontSize: 12, lineHeight: 1.7, color: 'var(--fg-2)', marginBottom: 4 }}>
            <strong style={{ color: 'var(--fg)' }}>{l.replace(' *', '')}</strong> — {MEASURE_HELP[k]}
          </div>
        ) : null)}
      </div>

      <div style={{ marginTop: 14 }}>
        <div style={labelStyle}>Additional notes</div>
        <textarea rows={2} value={fields.notes || ''} onChange={e => setF('notes', e.target.value)}
          placeholder="Posture notes, special requests, references…"
          style={{
            width: '100%', boxSizing: 'border-box', padding: '10px 12px',
            background: 'transparent', border: '.5px solid var(--line-2)',
            color: 'var(--fg)', fontFamily: 'var(--font-mono)', fontSize: 12,
            resize: 'vertical', outline: 'none',
          }}
          onFocus={e => e.target.style.borderColor = 'var(--fg)'}
          onBlur={e => e.target.style.borderColor = 'var(--line-2)'} />
      </div>
    </BStepShell>
  );
}

// ── Step 6: Review & add to cart ─────────────────────────────────────
function BStep6({ data, set }) {
  const loPrice = useCurrency();
  const p = data.product;
  const hide = BESPOKE_HIDES.find(h => h.id === data.hide);
  const leatherLabel = data.hide === 'nubuck'
    ? (data.nubuckFinish === 'distressed' ? 'Nubuck — Distressed' : 'Nubuck')
    : (hide?.label);
  const linerObj   = BESPOKE_LINERS.find(l => l.id === data.liner);
  const linerLabel = linerObj?.label;
  const linerAdd   = linerObj?.add || 0;
  // Bespoke atelier fee — amount + on/off set in admin → Discounts (server-authoritative).
  const _sc = (typeof window !== 'undefined' && window.SALE_CONFIG) || {};
  const bespokeFee = _sc.bespoke_fee === false ? 0 : (Number(_sc.bespoke_fee_amount) || 50);
  const NAT = window.NATURAL_COLORS || [];
  const DYE = window.DYED_COLORS    || [];
  const HW  = window.HARDWARE_COLORS || [];
  const allColors = [...NAT, ...DYE];
  const primHex   = allColors.find(c => c.name === data.primaryColor)?.hex;
  const secHex    = allColors.find(c => c.name === data.secondaryColor)?.hex;
  const hwHex     = HW.find(h => h.name === data.hardwareColor)?.hex;
  const secHwHex  = HW.find(h => h.name === data.secondaryHardwareColor)?.hex;

  const rows = [
    ['Jacket',             p?.frenchName || p?.name,               null      ],
    ['Leather',            leatherLabel,                            null      ],
    ['Liner',              linerAdd > 0 ? linerLabel + ' (+' + loPrice(linerAdd) + ')' : linerLabel, null ],
    ['Primary colour',     data.primaryColor,                       primHex   ],
    ['Secondary accent',   data.secondaryColor || '—',              secHex    ],
    ['Hardware',           data.hardwareColor,                      hwHex     ],
    ['Secondary hardware', data.secondaryHardwareColor || '—',      secHwHex  ],
    ['Size',               'Custom measurements',                   null      ],
  ];

  // Optional reference image — resized client-side to a small JPEG so it rides
  // safely in the cart and uploads quickly at checkout (handled server-side).
  const handleRefImage = (file) => {
    if (!file) return;
    if (!/^image\//.test(file.type)) { set('_refErr', 'Please choose an image file.'); return; }
    if (file.size > 20 * 1024 * 1024) { set('_refErr', 'That image is too large (max 20MB).'); return; }
    set('_refErr', null);
    const reader = new FileReader();
    reader.onload = (e) => {
      const img = new Image();
      img.onload = () => {
        const max = 1200;
        let w = img.width, h = img.height;
        if (w > max || h > max) { if (w >= h) { h = Math.round(h * max / w); w = max; } else { w = Math.round(w * max / h); h = max; } }
        const canvas = document.createElement('canvas');
        canvas.width = w; canvas.height = h;
        canvas.getContext('2d').drawImage(img, 0, 0, w, h);
        set('refImage', canvas.toDataURL('image/jpeg', 0.82));
      };
      img.onerror = () => set('_refErr', 'Could not read that image. Try another file.');
      img.src = e.target.result;
    };
    reader.onerror = () => set('_refErr', 'Could not read that file.');
    reader.readAsDataURL(file);
  };

  return (
    <BStepShell n={7}
      title={<><em>Review</em> your order.</>}
      sub="Everything looks right? Add it to your cart and check out. Your name, email, and shipping address are collected at checkout."
      data={data} set={set} stepKey="Review">

      <div style={{
        display: 'grid', gridTemplateColumns: '130px 1fr', gap: 28,
        padding: '22px', background: 'color-mix(in srgb,var(--fg) 3%,transparent)',
        border: '.5px solid var(--line)', marginBottom: 24,
      }}>
        <div style={{ aspectRatio: '3/4', overflow: 'hidden', background: 'var(--surface)' }}>
          {p?.images?.[0]
            ? <img src={p.images[0]} alt={p.name}
                style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
            : <div style={{ width: '100%', height: '100%', background: 'var(--surface)' }} />
          }
        </div>
        <div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--fg-3)', marginBottom: 4 }}>
            {p?.category} · Bespoke
          </div>
          <div className="display" style={{ fontSize: 26, lineHeight: 1, marginBottom: 12 }}>
            {p?.frenchName || p?.name}
          </div>
          {p && (
            <div style={{ marginBottom: 18 }}>
              <div className="display" style={{ fontSize: 22, color: 'var(--fg)' }}>{loPrice(p.price + bespokeFee + linerAdd)}</div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--fg-3)', marginTop: 3 }}>
                {loPrice(p.price)}{bespokeFee > 0 ? ' + ' + loPrice(bespokeFee) + ' bespoke atelier fee' : ''}{linerAdd > 0 ? ' + ' + loPrice(linerAdd) + ' ' + linerLabel + ' lining' : ''}
              </div>
            </div>
          )}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
            {rows.map(([k, v, hex]) => v ? (
              <div key={k} style={{
                display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                padding: '6px 0', borderBottom: '.5px solid var(--line-2)',
                fontFamily: 'var(--font-mono)', fontSize: 10,
              }}>
                <span style={{ color: 'var(--fg-3)', letterSpacing: '.12em', textTransform: 'uppercase' }}>{k}</span>
                <span style={{ display: 'flex', alignItems: 'center', gap: 7, color: 'var(--fg)' }}>
                  {hex && (
                    <span style={{
                      width: 10, height: 10, borderRadius: '50%', background: hex,
                      outline: '1px solid var(--line-2)', outlineOffset: 1, flexShrink: 0,
                    }}/>
                  )}
                  {v}
                </span>
              </div>
            ) : null)}
          </div>
        </div>
      </div>

      {/* Reference image — optional. Helps the atelier visualise the custom piece. */}
      <div style={{
        padding: '20px 22px', border: '.5px solid var(--line)',
        background: 'color-mix(in srgb,var(--fg) 2%,transparent)', marginBottom: 24,
      }}>
        <div className="mono" style={{ fontSize: 10, letterSpacing: '.14em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 10 }}>
          Reference image · optional
        </div>
        <p style={{ fontSize: 13, lineHeight: 1.65, color: 'var(--fg-2)', margin: '0 0 18px' }}>
          Have a picture of the jacket you're imagining? Add it and our atelier will match it as closely as possible.
          <span style={{ display: 'block', marginTop: 8, color: 'var(--fg-3)', fontSize: 12, lineHeight: 1.6 }}>
            <strong style={{ color: 'var(--fg-2)', fontWeight: 500 }}>Tip:</strong> drop the selections above into an AI image generator
            (ChatGPT, Midjourney, etc.) to create a visual of your custom piece — then upload that here. The clearer your
            reference, the closer we get it.
          </span>
        </p>

        {data.refImage ? (
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 16 }}>
            <div style={{ width: 120, aspectRatio: '3/4', overflow: 'hidden', border: '.5px solid var(--line-2)', background: 'var(--surface)' }}>
              <img src={data.refImage} alt="Your reference" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              <span className="mono" style={{ fontSize: 10, letterSpacing: '.1em', color: 'var(--fg-3)' }}>Reference attached ✓</span>
              <button type="button" onClick={() => { set('refImage', null); set('_refErr', null); }}
                style={{ background: 'transparent', border: '.5px solid var(--line-2)', color: 'var(--fg-2)', padding: '7px 16px', fontSize: 11, cursor: 'pointer', alignSelf: 'flex-start', letterSpacing: '.06em' }}>
                Remove
              </button>
            </div>
          </div>
        ) : (
          <label style={{
            display: 'inline-flex', alignItems: 'center', gap: 10, cursor: 'pointer',
            border: '.5px dashed var(--line-2)', padding: '14px 24px', color: 'var(--fg-2)', fontSize: 13,
            transition: 'border-color .15s, color .15s',
          }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--fg-3)'; e.currentTarget.style.color = 'var(--fg)'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--line-2)'; e.currentTarget.style.color = 'var(--fg-2)'; }}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
            Upload a reference image
            <input type="file" accept="image/*" style={{ display: 'none' }}
              onChange={e => handleRefImage(e.target.files && e.target.files[0])} />
          </label>
        )}
        {data._refErr && <div style={{ color: '#e57373', fontSize: 11, marginTop: 10 }}>{data._refErr}</div>}
      </div>

      <p className="mono" style={{ color: 'var(--fg-3)', fontSize: 10, lineHeight: 1.7 }}>
        {bespokeFee > 0 ? `Price shown includes the ${loPrice(bespokeFee)} bespoke atelier fee. ` : ''}Payment is taken at checkout — no waiting, no back-and-forth.
        Your piece goes straight into production once paid.
      </p>
    </BStepShell>
  );
}

// ── Main BespokeScreen ────────────────────────────────────────────────
function BespokeScreen({ open, onClose, initialProduct, initialCategory, addToCart }) {
  const firstStep = initialProduct ? 2 : 1;
  const [step, setStep] = React.useState(firstStep);
  const overlayRef = React.useRef(null);

  const blankData = () => ({
    category: initialCategory || (initialProduct?.category ?? null),
    gender:   initialProduct?.gender ?? null,
    product:  initialProduct ?? null,
    hide: null,
    nubuckFinish: 'normal',
    liner: null,
    primaryColor: null,
    secondaryColor: null,
    hardwareColor: null,
    secondaryHardwareColor: null,
    size: null,
    customFields: {},
    notes: {},
  });

  const [data, setData] = React.useState(blankData);
  const set = (k, v) => setData(d => ({ ...d, [k]: v }));

  React.useEffect(() => {
    if (open) {
      setStep(initialProduct ? 2 : 1);
      setData(blankData());
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = '';
    }
    return () => { document.body.style.overflow = ''; };
  }, [open, initialProduct?.id]);

  // Reset scroll before the browser paints the new step so the old scroll
  // position is never visible. useLayoutEffect fires synchronously after DOM
  // commit, before paint — useEffect would fire after and cause a flash.
  React.useLayoutEffect(() => {
    if (overlayRef.current) overlayRef.current.scrollTop = 0;
  }, [step]);

  const canAdvance = (() => {
    if (step === 1) return !!data.product;
    if (step === 2) return !!data.hide;
    if (step === 3) return !!data.liner;
    if (step === 4) return !!data.primaryColor;
    if (step === 5) return !!data.hardwareColor;
    if (step === 6) return !!(data.customFields?.chest && data.customFields?.shoulders && data.customFields?.sleeve);
    if (step === 7) return true;
    return false;
  })();

  const addToBag = () => {
    const hide = BESPOKE_HIDES.find(h => h.id === data.hide);
    const leatherLabel = data.hide === 'nubuck'
      ? (data.nubuckFinish === 'distressed' ? 'Nubuck — Distressed' : 'Nubuck')
      : (hide?.label || data.hide);
    const linerLabel = BESPOKE_LINERS.find(l => l.id === data.liner)?.label || null;
    const stepNotes = data.notes || {};
    const measNotes = ((data.customFields && data.customFields.notes) || '').trim();
    const combinedNotes = [
      ...Object.entries(stepNotes).filter(([, v]) => (v || '').trim()).map(([k, v]) => k + ': ' + v.trim()),
      measNotes ? ('Measurements: ' + measNotes) : '',
    ].filter(Boolean).join('\n');
    addToCart({
      id:         data.product.id,
      name:       data.product.name,
      frenchName: data.product.frenchName,
      price:      data.product.price,
      images:     data.product.images || [],
      qty:        1,
      size:       'Custom',
      color:      data.primaryColor || '',
      bespokeConfig: {
        style:               data.category,
        product:             data.product.frenchName || data.product.name,
        product_image:       data.product.images?.[0] || '',
        leather:             leatherLabel,
        liner:               linerLabel,
        primary_color:       data.primaryColor,
        secondary_color:     data.secondaryColor   || null,
        hardware:            data.hardwareColor,
        secondary_hardware:  data.secondaryHardwareColor || null,
        size:                'Custom',
        custom_measurements: data.customFields,
        step_notes:          stepNotes,
        notes:               combinedNotes || null,
        ordered_for_name:         data.orderedForName || null,
        ordered_for_relationship: data.orderedForRelationship || null,
      },
      refImage: data.refImage || null,
    });
    onClose();
  };

  if (!open) return null;

  const NAT = window.NATURAL_COLORS || [];
  const DYE = window.DYED_COLORS || [];
  const allColors = [...NAT, ...DYE];
  const primHex = allColors.find(c => c.name === data.primaryColor)?.hex;

  return (
    <div ref={overlayRef} className="bespoke-overlay" role="dialog" aria-modal="true">

      {/* ── Sticky header ── */}
      <header className="bespoke-head">
        <div className="bespoke-head-inner container">

          {/* Back / close */}
          <button className="commission-back"
            onClick={() => step > firstStep ? setStep(step - 1) : onClose()}>
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
              stroke="currentColor" strokeWidth="1.3">
              <path d="M8.5 2 3 7l5.5 5" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
            {step > firstStep ? 'Back' : 'Close'}
          </button>

          {/* Step pills */}
          <div className="bespoke-pills">
            {BSTEPS.map((label, i) => {
              const n = i + 1;
              return (
                <span key={n} className={`bespoke-pill${n === step ? ' active' : ''}${n < step ? ' done' : ''}`}>
                  <span className="bespoke-pill-num">{n < step ? '✓' : n}</span>
                  <span className="bespoke-pill-label">{label}</span>
                </span>
              );
            })}
          </div>

          {/* Close X */}
          <button className="commission-close" onClick={onClose} aria-label="Close">
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
              stroke="currentColor" strokeWidth="1.3">
              <line x1="2" y1="2" x2="12" y2="12"/>
              <line x1="12" y1="2" x2="2" y2="12"/>
            </svg>
          </button>
        </div>

        {/* Context bar: shows chosen product + selections as you progress */}
        {data.product && step > 1 && (
          <div className="bespoke-context">
            <div className="container bespoke-context-inner">
              {data.product.images?.[0] && (
                <img src={data.product.images[0]} alt={data.product.name}
                  style={{ width: 34, height: 44, objectFit: 'contain', flexShrink: 0 }} />
              )}
              <div>
                <div className="mono" style={{ fontSize: 9.5, color: 'var(--fg-3)', letterSpacing: '.12em', textTransform: 'uppercase' }}>
                  {data.product.category}
                </div>
                <div className="mono" style={{ fontSize: 11, color: 'var(--fg)' }}>
                  {data.product.frenchName || data.product.name}
                </div>
              </div>
              {data.hide && (
                <span className="commission-chip" style={{ color: 'var(--fg-3)' }}>
                  {BESPOKE_HIDES.find(h => h.id === data.hide)?.label}
                </span>
              )}
              {data.primaryColor && (
                <span className="commission-chip" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  {primHex && (
                    <span style={{
                      width: 8, height: 8, borderRadius: '50%', background: primHex,
                      outline: '1px solid var(--line-2)', outlineOffset: 1,
                    }}/>
                  )}
                  {data.primaryColor}
                </span>
              )}
              {data.hardwareColor && (
                <span className="commission-chip" style={{ color: 'var(--fg-3)' }}>
                  {data.hardwareColor}
                </span>
              )}
              {data.size && (
                <span className="commission-chip">
                  {data.size}
                </span>
              )}
            </div>
          </div>
        )}
      </header>

      {/* ── Body ── */}
      <div className="bespoke-body">
        <BStepError>
          <div key={step} className="bstep-anim">
            {step === 1 && <BStep1 data={data} set={set} />}
            {step === 2 && <BStep2 data={data} set={set} />}
            {step === 3 && <BStepLiner data={data} set={set} />}
            {step === 4 && <BStep3 data={data} set={set} />}
            {step === 5 && <BStep4 data={data} set={set} />}
            {step === 6 && <BStep5 data={data} set={set} />}
            {step === 7 && <BStep6 data={data} set={set} />}
          </div>
        </BStepError>
      </div>

      {/* ── Footer ── */}
      <footer className="commission-foot">
        <div className="container commission-foot-inner">
          <div className="commission-summary">
            <span className="mono" style={{ color: 'var(--fg-3)' }}>
              Step {step} of {BSTEPS.length} · {BSTEPS[step - 1]}
            </span>
            {data.product && step >= 2 && (
              <span className="commission-chip">{data.product.frenchName || data.product.name}</span>
            )}
          </div>
          {step < BSTEPS.length ? (
            <button className="btn" disabled={!canAdvance}
              onClick={() => canAdvance && setStep(step + 1)}
              style={{ opacity: canAdvance ? 1 : .4, cursor: canAdvance ? 'pointer' : 'not-allowed' }}>
              Continue <span className="arrow">→</span>
            </button>
          ) : (
            <button className="btn" onClick={addToBag}>
              Add to Cart <span className="arrow">→</span>
            </button>
          )}
        </div>
      </footer>
    </div>
  );
}

Object.assign(window, { BespokeScreen });
