{
  "version": 3,
  "sources": ["/cdn/shop/t/3/assets/js-shop.js?cbx=1791111608596"],
  "sourcesContent": ["/* ==========================================================================\n   Vision Attire \u2014 Shopify bridge\n   On the Shopify theme this swaps the catalogue's placeholder stock for the\n   store's live variants, adds to the real cart and keeps the bag count. On\n   Netlify staging window.Shopify doesn't exist, VA_SHOP stays undefined and\n   every page runs exactly as before.\n\n   The catalogue keeps the design data (photos, swatches, copy). Shopify owns\n   what it should: variant IDs, prices and whether a size is in stock. The link\n   between them is a handle rule plus the overrides in shopify.json:\n     colourway `royal-blue` in collection `mens-physique-shorts`\n       -> Shopify product `mens-physique-shorts-royal-blue`\n     unless shopify.json says e.g. { \"product\": \"bodybuilding-trunks\", \"colour\": \"Metallic Blue\" }\n   ========================================================================== */\n(() => {\n  'use strict';\n  if (!window.Shopify || !Shopify.shop) return;\n\n  const root = (Shopify.routes && Shopify.routes.root) || '/';\n  const norm = (s) => String(s ?? '').toLowerCase().replace(/[^a-z0-9.]/g, '');\n  const num = (s) => { const m = String(s ?? '').match(/\\d+(\\.\\d+)?/); return m ? +m[0] : null; };\n  // Shorts are sized by waist (26\") and trunks by letter (M, 2XL): keep a letter as its label.\n  const sizeOf = (s) => /^\\s*\\d+(\\.\\d+)?\\s*(\"|\u201D|\u2033|in)?\\s*$/i.test(String(s ?? '')) ? num(s) : (String(s ?? '').trim().toUpperCase() || null);\n  const json = (r) => { if (!r.ok) throw new Error(r.status + ' ' + r.url); return r.json(); };\n\n  const mapReady = fetch(VA_DATA('assets/data/shopify.json')).then(json).catch(() => ({}));\n  const products = {};\n  const product = (handle) => products[handle] || (products[handle] =\n    fetch(root + 'products/' + encodeURIComponent(handle) + '.js').then(json).catch(() => null));\n\n  // Which position holds size, length and colour, by option name.\n  function slots(p, names) {\n    const list = (p.options || []).map(o => norm(typeof o === 'string' ? o : o.name));\n    const find = (keys) => list.findIndex(n => keys.some(k => norm(k) === n));\n    return {\n      size: find(names.size || ['Size', 'Waist', 'Waist size']),\n      length: find(names.length || ['Length']),\n      colour: find(names.colour || ['Colour', 'Color', 'Colourway', 'Cut', 'Style']),\n    };\n  }\n\n  function entryFor(map, coll, cw) {\n    const c = (map.colourways || {})[coll.handle] || {}, all = c['*'];\n    const o = c[cw.handle] || (all ? { product: all.product, colour: cw.title } : {});\n    return { product: o.product || coll.handle + '-' + cw.handle, colour: o.colour || null };\n  }\n\n  /* Returns the catalogue with live stock, prices and variants. A colourway\n     whose Shopify product can't be found is marked out and flagged `missing`,\n     so a mapping mistake shows as \"sold out\" on the page and a console warning,\n     never as an add-to-cart that fails. */\n  async function live(cat) {\n    const map = await mapReady;\n    await Promise.all((cat.collections || []).flatMap(coll => coll.products.map(async cw => {\n      const e = entryFor(map, coll, cw), p = await product(e.product);\n      if (!p) { cw.stock = 'out'; cw.missing = true; cw.variants = [];\n        console.warn('[va-shop] no Shopify product for', coll.handle, cw.handle, '->', e.product); return; }\n      const s = slots(p, map.optionNames || {});\n      cw.variants = p.variants\n        .filter(v => !e.colour || s.colour < 0 || norm(v.options[s.colour]) === norm(e.colour))\n        .map(v => ({ id: v.id, available: v.available, price: v.price / 100,\n                     size: s.size < 0 ? null : sizeOf(v.options[s.size]),\n                     length: s.length < 0 ? null : num(v.options[s.length]) }));\n      if (!cw.variants.length) console.warn('[va-shop] no variants match', e);\n      const avail = cw.variants.filter(v => v.available);\n      cw.stock = avail.length ? (avail.length <= Math.ceil(cw.variants.length / 4) ? 'low' : 'in') : 'out';\n      cw.shopifyUrl = p.url;\n      if (cw.variants.length) cw.price = Math.min(...cw.variants.map(v => v.price));\n    })));\n    (cat.collections || []).forEach(c => {\n      const prices = c.products.map(p => p.price).filter(x => x != null);\n      if (prices.length) c.price = Math.min(...prices);\n    });\n    return cat;\n  }\n\n  // The variant for a size and length, or null. Missing slots on the product\n  // (a trunk has no length) match anything.\n  function variant(cw, size, length) {\n    return (cw.variants || []).find(v =>\n      (size == null || v.size == null || String(v.size).toUpperCase() === String(size).toUpperCase()) &&\n      (length == null || v.length == null || v.length === +length)) || null;\n  }\n\n  // Every size the store sells across a collection's colourways, in shop order:\n  // waists ascending, then letters S to 3XL. Empty when nothing mapped.\n  const ORDER = ['XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL', '2XL', '3XL', '4XL'];\n  function sizes(coll) {\n    const all = [...new Set(coll.products.flatMap(p => (p.variants || []).map(v => v.size)).filter(x => x != null))];\n    const rank = (x) => typeof x === 'number' ? x : 1000 + (ORDER.includes(x) ? ORDER.indexOf(x) : 99);\n    return all.sort((a, b) => rank(a) - rank(b));\n  }\n\n  /* --- bag -------------------------------------------------------------- */\n  let count = 0;\n  function paintBag(n) {\n    count = n;\n    document.querySelectorAll('[data-cart]').forEach(a => {\n      a.hidden = false;\n      a.classList.toggle('is-full', n > 0);\n      a.setAttribute('aria-label', `Your bag, ${n} item${n === 1 ? '' : 's'}`);\n      const b = a.querySelector('[data-cart-count]'); if (b) b.textContent = n;\n    });\n  }\n  const refresh = () => fetch(root + 'cart.js').then(json).then(c => paintBag(c.item_count)).catch(() => paintBag(count));\n\n  async function add(items) {\n    const r = await fetch(root + 'cart/add.js', {\n      method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n      body: JSON.stringify({ items }),\n    });\n    const body = await r.json().catch(() => ({}));\n    if (!r.ok) throw new Error(body.description || body.message || 'Could not add to your bag');\n    await refresh();\n    return body;\n  }\n\n  /* Custom Colour deposit: the deposit product's single variant, plus one\n     extras variant per chosen extra. Both are priced in Shopify at half the\n     full price, so checkout takes exactly the 50% the builder shows. */\n  async function addCustom({ extras = [], properties = {}, expectDeposit }) {\n    const map = await mapReady, c = map.custom || {};\n    const dep = await product(c.deposit || 'custom-colour-deposit');\n    if (!dep || !dep.variants.length) throw new Error('The custom deposit product is not set up in the store yet');\n    const items = [{ id: dep.variants[0].id, quantity: 1, properties }];\n    let charged = dep.variants[0].price / 100;\n    if (extras.length) {\n      const ex = await product(c.extras || 'custom-order-extras');\n      const names = c.extraOptions || {};\n      for (const id of extras) {\n        const want = norm(names[id] || id);\n        const v = ex && ex.variants.find(x => norm(x.title) === want || x.options.some(o => norm(o) === want));\n        if (!v) throw new Error(`The \"${names[id] || id}\" extra is not set up in the store yet`);\n        items.push({ id: v.id, quantity: 1, properties: { 'Design ref': properties['Design ref'] } });\n        charged += v.price / 100;\n      }\n    }\n    // The page promised a figure. If the store's prices have drifted from the\n    // builder's, stop rather than charge something different.\n    if (expectDeposit != null && Math.abs(charged - expectDeposit) > 0.009)\n      throw new Error(`The deposit in the store ($${charged.toFixed(2)}) doesn't match this design ($${expectDeposit.toFixed(2)})`);\n    return add(items);\n  }\n\n  window.VA_SHOP = { live, variant, sizes, add, addCustom, refresh, cartUrl: root + 'cart' };\n  refresh();\n  // Back-button restores from the page cache show a stale count.\n  addEventListener('pageshow', e => { if (e.persisted) refresh(); });\n})();\n"],
  "mappings": "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",
  "names": []
}
