{
  "version": 3,
  "sources": ["/cdn/shop/t/29/assets/ai-design-attach.js?build=20260510b"],
  "sourcesContent": ["/**\n * AI Design product-page attach \u2014 Phase 3b (revised)\n *\n * Loads on every page. On product pages with file-upload inputs (any number of\n * print locations / variants), this:\n *\n *   1. Adds a small \"\u2728 Or use a saved AI design\" link directly below each\n *      file input \u2014 visible only when the customer's library has designs.\n *   2. On selection, fetches the chosen design as a blob and assigns it to\n *      THAT specific file input via the DataTransfer API. From the host\n *      page's perspective it's indistinguishable from a normal upload, so\n *      the existing per-location pricing / preview UI just works.\n *   3. Also drops a marketing banner at the top of the cart form pointing\n *      to /pages/design-with-ai for customers who haven't designed anything\n *      yet.\n *   4. Shows a confirmation chip below the input after AI design is selected\n *      so the customer can see what's attached and clear it if they want.\n *\n * No standalone \"Use AI design\" panel \u2014 everything is per-upload-field, so\n * staff and customers always know which design goes to which print location.\n */\n(function () {\n  // === Constants \u2014 must be declared BEFORE any function that uses them is\n  // executed. (Top-level `const` is hoisted to the IIFE scope but lives in the\n  // temporal dead zone until this point, so calls to start()/init()/etc. that\n  // reference these would throw a ReferenceError if placed earlier.)\n  const LINK_CLASS = \"ai-attach-link\";\n  const CHIP_CLASS = \"ai-attach-chip\";\n  const BANNER_CLASS = \"ai-attach-banner\";\n\n  function start() {\n    if (!window.AIDesignLibrary || !window.AIDesignFetch) {\n      setTimeout(start, 100);\n      return;\n    }\n    init();\n  }\n\n  function init() {\n    // Skip injection on our own designer / my-designs pages \u2014 banner +\n    // per-input link don't belong there (they ARE the source of designs).\n    // Also skip on the DTF Gang Sheet Builder: AI-generated designs aren't\n    // set up for gang sheet printing (wrong DPI, wrong colour mode, no\n    // transparent background) so offering them there just leads to failed\n    // orders.\n    if (\n      document.querySelector(\".ai-chat\") ||\n      document.querySelector(\".my-designs\") ||\n      document.querySelector(\"[data-gang-sheet-builder]\")\n    ) {\n      console.log(\"[ai-design-attach] skipping on designer/my-designs/gang-sheet page\");\n      return;\n    }\n\n    console.log(\"[ai-design-attach] init on\", location.pathname);\n    enhanceAllForms();\n\n    // Some themes inject cart forms / upload inputs after page load\n    // (variant pickers, cart drawers, lazy-loaded sections).\n    const obs = new MutationObserver(function () {\n      enhanceAllForms();\n    });\n    obs.observe(document.body, { childList: true, subtree: true });\n\n    // Re-evaluate visibility when the library changes (e.g. tab focused\n    // after generating a new design in another tab).\n    window.addEventListener(\"storage\", function (e) {\n      if (e && e.key && e.key.indexOf(\"ai_design_library\") === 0) {\n        refreshVisibility();\n      }\n    });\n    window.addEventListener(\"focus\", refreshVisibility);\n  }\n\n  function enhanceAllForms() {\n    // Find every file input on the page. We don't filter by name or URL \u2014\n    // file inputs are rare enough on a typical site that any one we find\n    // is likely a customer artwork upload. False positives are harmless\n    // (the link would just appear next to an unrelated input).\n    const fileInputs = document.querySelectorAll('input[type=\"file\"]');\n    console.log(\n      \"[ai-design-attach] found\",\n      fileInputs.length,\n      \"file inputs:\",\n      Array.from(fileInputs).map(function (i) { return i.name || \"(no name)\"; })\n    );\n\n    fileInputs.forEach(injectLinkBesideInput);\n\n    // Marketing banner \u2014 inject once, into a prominent spot that's visible\n    // BEFORE the customer has interacted with anything (i.e. not hiding\n    // behind an unexpanded upload widget).\n    if (!document.querySelector(\".\" + BANNER_CLASS)) {\n      injectMarketingBannerStandalone();\n    }\n    refreshVisibility();\n\n    // If the customer arrived from the chat with a pending design, attach\n    // it to the most appropriate input. Idempotent \u2014 safe to call multiple\n    // times (clears the sessionStorage flag once consumed).\n    consumePendingFromChat();\n  }\n\n  // ============= Auto-attach from chat =============\n  /**\n   * When the customer clicks \"Put it on a tee \u2192\" in chat, ai-designer.js\n   * sets `sessionStorage.ai_design_pending = { url, prompt, ts }`. This\n   * function picks up that flag on product pages, finds the best file\n   * input (Large Front Print preferred), attaches the design programmatically,\n   * pre-checks the print-location checkbox if there is one, shows a\n   * confirmation toast, and clears the flag.\n   *\n   * Self-throttled \u2014 only runs once per page load (or until inputs appear).\n   */\n  let _consumeAttempts = 0;\n  function consumePendingFromChat() {\n    let pending;\n    try {\n      const raw = sessionStorage.getItem(\"ai_design_pending\");\n      if (!raw) return;\n      pending = JSON.parse(raw);\n    } catch (_) { return; }\n\n    if (!pending || !pending.url) {\n      sessionStorage.removeItem(\"ai_design_pending\");\n      return;\n    }\n\n    // Stale flag (>1h old) \u2014 discard rather than auto-attach an old design.\n    if (pending.ts && Date.now() - pending.ts > 60 * 60 * 1000) {\n      sessionStorage.removeItem(\"ai_design_pending\");\n      return;\n    }\n\n    const input = pickPreferredInputForChatDesign();\n    if (!input) {\n      // Inputs not enhanced yet \u2014 try again on next mutation cycle, up to a\n      // few attempts so we don't loop forever on pages with no inputs.\n      _consumeAttempts++;\n      if (_consumeAttempts > 20) return;\n      setTimeout(consumePendingFromChat, 300);\n      return;\n    }\n\n    const wrap = input._aiAttachWrap;\n    if (!wrap) return;\n\n    // Pre-check the matching print-location checkbox if there is one.\n    // Print location selector uses ID pattern `pls-<key>` for checkbox and\n    // `pls-<key>-file` for the input. So strip \"-file\" off the end.\n    const checkboxId = (input.id || \"\").replace(/-file$/, \"\");\n    if (checkboxId && checkboxId !== input.id) {\n      const checkbox = document.getElementById(checkboxId);\n      if (checkbox && checkbox.type === \"checkbox\" && !checkbox.checked) {\n        checkbox.checked = true;\n        checkbox.dispatchEvent(new Event(\"change\", { bubbles: true }));\n      }\n    }\n\n    // Synthesize a design object matching what assignDesignToInput expects.\n    const design = {\n      id: \"from-chat-\" + Date.now(),\n      draftUrl: pending.url,\n      prompt: pending.prompt || \"\",\n      thumbnail: pending.url,\n    };\n\n    // Clear flag IMMEDIATELY so a refresh doesn't re-attach. We do this\n    // before the async assign so race-condition refreshes are safe.\n    sessionStorage.removeItem(\"ai_design_pending\");\n\n    assignDesignToInput(input, design, wrap);\n\n    // Confirmation toast at top of page so the customer knows the design\n    // was added without them having to do anything.\n    showAttachToast(\n      \"\u2713 Your AI design is attached. Pick a size below and add to cart.\"\n    );\n\n    // Pulse any other \"Use my AI design\" links in case the customer wants\n    // to swap to a different saved design \u2014 guides their eye there.\n    setTimeout(function () {\n      document.querySelectorAll(\".\" + LINK_CLASS).forEach(function (el) {\n        el.classList.add(LINK_CLASS + \"--from-chat\");\n      });\n    }, 100);\n  }\n\n  /**\n   * Pick the best file input for an AI design coming from chat. Priority:\n   *   1. An input whose context says \"Large Front\" (where AI designs go best)\n   *   2. An input on the front side that isn't a small-area chest print\n   *   3. Any front-side input\n   *   4. The first input on the page\n   * Only considers inputs we've enhanced (have an attached wrap).\n   */\n  function pickPreferredInputForChatDesign() {\n    const enhanced = Array.from(document.querySelectorAll('input[type=\"file\"]'))\n      .filter(function (i) { return !!i._aiAttachWrap; });\n    if (!enhanced.length) return null;\n\n    // 1. Large/Full Front\n    for (const input of enhanced) {\n      const ctx = buildInputContext(input);\n      if (/\\blarge\\s*front\\b|\\bfront\\s*large\\b|\\bfull\\s*front\\b|\\bfront\\s*full\\b/.test(ctx)) {\n        return input;\n      }\n    }\n    // 2. Front (no back, no small chest)\n    for (const input of enhanced) {\n      const ctx = buildInputContext(input);\n      if (/\\bfront\\b/.test(ctx) && !/\\bback\\b/.test(ctx) &&\n          !/\\bleft\\s*chest\\b/.test(ctx)) {\n        return input;\n      }\n    }\n    // 3. Any front side\n    for (const input of enhanced) {\n      if (sideForInput(input) === \"front\") return input;\n    }\n    // 4. Fallback \u2014 first enhanced input\n    return enhanced[0];\n  }\n\n  /** Lightweight top-of-page toast confirming the auto-attach happened. */\n  function showAttachToast(text) {\n    const t = document.createElement(\"div\");\n    t.className = \"ai-attach-toast\";\n    t.innerHTML =\n      '<span class=\"ai-attach-toast__icon\" aria-hidden=\"true\">\u2713</span>' +\n      '<span>' + text + '</span>';\n    document.body.appendChild(t);\n    setTimeout(function () {\n      t.style.transition = \"opacity 0.4s ease, transform 0.4s ease\";\n      t.style.opacity = \"0\";\n      t.style.transform = \"translate(-50%, -8px)\";\n      setTimeout(function () { t.remove(); }, 400);\n    }, 4500);\n  }\n\n  function injectMarketingBannerStandalone() {\n    if (document.body.classList.contains(\"template-index\")) return;\n    const cfg = window.AIDesignConfig || {};\n    const designerUrl = cfg.designerUrl || \"/pages/design-with-ai\";\n\n    const banner = document.createElement(\"a\");\n    banner.className = BANNER_CLASS;\n    banner.href = designerUrl;\n    // Copy matched to snippets/ft-ai-entry.liquid's equivalent entry point\n    // on the order-builder-ready path \u2014 same wording, not just same\n    // colours (2026-09-04, \"they all need to... appear as the same\n    // system\").\n    banner.innerHTML =\n      '<span class=\"' + BANNER_CLASS + '__icon\">\u2728</span>' +\n      '<span class=\"' + BANNER_CLASS + '__text\">' +\n        '<strong>Don\u2019t have a design ready?</strong> ' +\n        'Try our AI designer \u2014 see it on a shirt before you order \u2192' +\n      '</span>';\n\n    const target = findBannerTarget();\n    if (!target) {\n      console.log(\"[ai-design-attach] no banner target found yet, will retry\");\n      return; // MutationObserver will retry on subsequent DOM changes\n    }\n    target.insertBefore.call(target.parentNode, banner, target);\n  }\n\n  /**\n   * Find the best on-page anchor to put the banner ABOVE.\n   * Tried in priority order:\n   *   1. The \"Send your design when you're ready\" callout (or anything with\n   *      similar text \u2014 most prominent existing artwork UI on this product).\n   *   2. The Print Locations section / HulkApps wrapper.\n   *   3. The product form (above the cart submit area).\n   *   4. The first file input (fallback).\n   *\n   * Returns the element to INSERT BEFORE, or null if no suitable spot found.\n   */\n  function findBannerTarget() {\n    // Priority 1 \u2014 locate by text. Walk all reasonable container elements\n    // looking for the \"Send your design\" callout (common on print stores).\n    const SEARCH_TERMS = [\n      \"send your design\",\n      \"send your artwork\",\n      \"upload your artwork\",\n      \"upload your design\",\n      \"your artwork\",\n    ];\n    const candidates = document.querySelectorAll(\n      \"div, section, fieldset, aside, p\"\n    );\n    for (let i = 0; i < candidates.length; i++) {\n      const el = candidates[i];\n      const text = (el.textContent || \"\").trim().toLowerCase();\n      // Only match the smallest container that actually contains the phrase,\n      // i.e. the element's own text (not just ancestor text). We pick\n      // elements with relatively short text content so we don't grab the\n      // whole product wrapper.\n      if (text.length > 600) continue;\n      for (let j = 0; j < SEARCH_TERMS.length; j++) {\n        if (text.indexOf(SEARCH_TERMS[j]) !== -1) {\n          return el;\n        }\n      }\n    }\n\n    // Priority 2 \u2014 Print Locations / HulkApps section by class names.\n    const cls = document.querySelector(\n      \"[class*='pls'], [class*='print-loc'], [class*='hulk'], [class*='upload']\"\n    );\n    if (cls) return cls;\n\n    // Priority 3 \u2014 the product form's first child.\n    const form = document.querySelector(\n      'form[action*=\"/cart/add\"], form[action$=\"/cart\"], form.product-form'\n    );\n    if (form && form.firstElementChild) return form.firstElementChild;\n\n    // Priority 4 \u2014 fallback to first file input.\n    const firstInput = document.querySelector('input[type=\"file\"]');\n    if (firstInput) return firstInput;\n\n    return null;\n  }\n\n  function injectLinkBesideInput(input) {\n    if (input.dataset.aiAttached === \"1\") return;\n    input.dataset.aiAttached = \"1\";\n\n    // Skip \"fake\" file inputs that aren't really for uploads (some themes\n    // have hidden form-level inputs for tracking).\n    if (input.style.display === \"none\" && input.offsetParent === null) {\n      // Hidden input \u2014 but it might still be the real upload field, just\n      // styled away. We still attach to it; visibility check below decides\n      // whether the link itself is shown.\n    }\n\n    // Find the wrapping container so we insert the link below the visible\n    // upload area, not next to a hidden <input> tucked inside.\n    const insertionTarget = findInsertionTarget(input);\n\n    const wrap = document.createElement(\"div\");\n    wrap.className = LINK_CLASS + \"__wrap\";\n\n    const link = document.createElement(\"button\");\n    link.type = \"button\";\n    link.className = LINK_CLASS;\n    link.dataset.aiTargetInput = \"1\"; // marker for refreshVisibility\n    link.innerHTML =\n      '<span class=\"' + LINK_CLASS + '__icon\">\u2728</span>' +\n      '<span>Use my AI design</span>';\n    link.addEventListener(\"click\", function () {\n      openLibraryModal({\n        onPick: function (design) {\n          assignDesignToInput(input, design, wrap);\n        },\n      });\n    });\n\n    // Stash the wrap on the input so consumePendingFromChat() can find it\n    // when auto-attaching a design from the chat.\n    input._aiAttachWrap = wrap;\n\n    const chip = document.createElement(\"div\");\n    chip.className = CHIP_CLASS;\n    chip.hidden = true;\n    chip.innerHTML =\n      '<img class=\"' + CHIP_CLASS + '__thumb\" alt=\"\" />' +\n      '<div class=\"' + CHIP_CLASS + '__text\">' +\n        '<strong class=\"' + CHIP_CLASS + '__prompt\"></strong>' +\n        '<span class=\"' + CHIP_CLASS + '__status\">\u2713 AI design ready to upload</span>' +\n      '</div>' +\n      '<button type=\"button\" class=\"' + CHIP_CLASS + '__clear\" aria-label=\"Remove design\" title=\"Remove design\">\u00D7</button>';\n    chip\n      .querySelector(\".\" + CHIP_CLASS + \"__clear\")\n      .addEventListener(\"click\", function () {\n        clearInput(input, wrap);\n      });\n\n    // Live mockup preview canvas (hidden until a design is attached)\n    const mockup = document.createElement(\"div\");\n    mockup.className = \"ai-attach-mockup\";\n    mockup.hidden = true;\n    mockup.innerHTML =\n      '<div class=\"ai-attach-mockup__inner\">' +\n      '  <span class=\"ai-attach-mockup__loading\">Rendering preview\u2026</span>' +\n      '</div>' +\n      '<p class=\"ai-attach-mockup__caption\">Position not quite right? That\\'s OK! Just let me know in the order notes and the team will fix it up for you.</p>';\n\n    wrap.appendChild(link);\n    wrap.appendChild(chip);\n    wrap.appendChild(mockup);\n\n    insertionTarget.parentNode.insertBefore(wrap, insertionTarget.nextSibling);\n  }\n\n  /**\n   * Find the visible container we should anchor our link under. We walk up\n   * from the file input looking for a \"card-like\" parent (label, .upload,\n   * fieldset, file-upload, custom upload widget). Falls back to the input's\n   * direct parent.\n   */\n  function findInsertionTarget(input) {\n    const SELECTORS = [\n      \"label\",\n      \"fieldset\",\n      \"[data-upload]\",\n      \"[class*='upload']\",\n      \"[class*='file-input']\",\n      \"[class*='dropzone']\",\n    ];\n    let current = input.parentElement;\n    let depth = 0;\n    while (current && depth < 6) {\n      for (let i = 0; i < SELECTORS.length; i++) {\n        if (current.matches(SELECTORS[i])) return current;\n      }\n      current = current.parentElement;\n      depth++;\n    }\n    return input;\n  }\n\n  async function assignDesignToInput(input, design, wrap) {\n    const link = wrap.querySelector(\".\" + LINK_CLASS);\n    const chip = wrap.querySelector(\".\" + CHIP_CLASS);\n    const original = link.innerHTML;\n    link.disabled = true;\n    link.innerHTML =\n      '<span class=\"' + LINK_CLASS + '__icon\">\u23F3</span>' +\n      '<span>Adding your design\u2026</span>';\n\n    try {\n      const blob = await window.AIDesignFetch.fetchBlob(design.draftUrl);\n      const slug = (design.prompt || \"design\")\n        .slice(0, 32)\n        .replace(/[^a-z0-9-_]+/gi, \"-\");\n      const file = new File([blob], \"ai-design-\" + slug + \".png\", {\n        type: blob.type || \"image/png\",\n      });\n\n      const dt = new DataTransfer();\n      dt.items.add(file);\n      input.files = dt.files;\n      input.dispatchEvent(new Event(\"change\", { bubbles: true }));\n      input.dispatchEvent(new Event(\"input\", { bubbles: true }));\n\n      // Keep the exact selected design URL. Production preparation belongs to staff.\n      const idBase = (input.id || \"\").replace(/-file$/, \"\");\n      if (idBase) {\n        const statusProp = document.getElementById(idBase + \"-status-prop\");\n        if (statusProp) statusProp.value = \"\u2713 Received \u2014 \" + file.name;\n        const urlProp = document.getElementById(idBase + \"-url\");\n        if (urlProp) urlProp.value = design.draftUrl || \"\";\n        console.log(\n          \"[ai-design-attach] populated line-item URL on \" + idBase + \":\",\n          urlProp ? urlProp.value : \"(no urlProp el)\"\n        );\n      } else {\n        console.warn(\n          \"[ai-design-attach] couldn't derive idBase from input id; URL property NOT set\",\n          { inputId: input.id }\n        );\n      }\n\n      // Show confirmation chip\n      chip.querySelector(\".\" + CHIP_CLASS + \"__thumb\").src =\n        design.thumbnail || design.draftUrl;\n      chip.querySelector(\".\" + CHIP_CLASS + \"__prompt\").textContent =\n        (design.prompt || \"(no prompt)\").slice(0, 80);\n      chip.hidden = false;\n      link.hidden = true;\n\n      // Hide HulkApps's \"No file? You can upload later\" hint that's tied\n      // to their own state, not input.files \u2014 so it's misleading once we've\n      // attached a design.\n      hideHostNoFileHints(input);\n\n      // Live mockup preview \u2014 composite design over product image\n      renderMockup(input, design, wrap).catch(function (e) {\n        console.warn(\"Mockup render failed\", e);\n      });\n\n      if (window.AIDesignShare && window.AIDesignShare.toast) {\n        window.AIDesignShare.toast(\"\u2713 AI design attached\");\n      }\n\n      // Keep the exact selected AI source. Staff review and prepare production artwork.\n    } catch (err) {\n      console.error(err);\n      if (window.AIDesignShare && window.AIDesignShare.toast) {\n        window.AIDesignShare.toast(\n          \"Couldn't attach: \" + (err.message || \"unknown error\")\n        );\n      }\n      link.disabled = false;\n      link.innerHTML = original;\n    }\n  }\n\n  /** XHR-based JSON POST \u2014 Shopify's fetch wrappers break worker responses. */\n  function xhrPostJson(url, body) {\n    return new Promise(function (resolve, reject) {\n      const xhr = new XMLHttpRequest();\n      xhr.open(\"POST\", url, true);\n      xhr.setRequestHeader(\"Content-Type\", \"application/json\");\n      xhr.setRequestHeader(\"Accept\", \"application/json\");\n      xhr.timeout = 90000; // print regen at 2880\u00B2 takes 30-60s\n      xhr.onload = function () {\n        try {\n          const data = JSON.parse(xhr.responseText || \"{}\");\n          if (xhr.status >= 200 && xhr.status < 300) resolve(data);\n          else reject(new Error(data.error || (\"HTTP \" + xhr.status)));\n        } catch (e) { reject(e); }\n      };\n      xhr.onerror = function () { reject(new Error(\"Network error\")); };\n      xhr.ontimeout = function () { reject(new Error(\"Print regen timed out\")); };\n      xhr.send(JSON.stringify(body));\n    });\n  }\n\n  function clearInput(input, wrap) {\n    try {\n      input.value = \"\";\n      const dt = new DataTransfer();\n      input.files = dt.files;\n    } catch (_) {}\n    input.dispatchEvent(new Event(\"change\", { bubbles: true }));\n\n    const link = wrap.querySelector(\".\" + LINK_CLASS);\n    const chip = wrap.querySelector(\".\" + CHIP_CLASS);\n    const mockup = wrap.querySelector(\".ai-attach-mockup\");\n    chip.hidden = true;\n    if (mockup) mockup.hidden = true;\n    link.hidden = false;\n    link.disabled = false;\n    link.innerHTML =\n      '<span class=\"' + LINK_CLASS + '__icon\">\u2728</span>' +\n      '<span>Use my AI design</span>';\n\n    // Restore any host-page \"no file\" hints we hid when the design was attached.\n    restoreHostNoFileHints(input);\n  }\n\n  /**\n   * Hide host-page \"No file? You can upload later after ordering\" hints (and\n   * similar messages) within the same upload area as `input`. Scans nearby\n   * ancestors for visible text containing the no-file phrase and toggles\n   * `display: none`, tagging hidden nodes so we can restore them later.\n   *\n   * Apps like HulkApps render these hints based on their own state and won't\n   * update when we attach a file via DataTransfer \u2014 so we have to hide\n   * them ourselves to avoid confusing the customer.\n   */\n  function hideHostNoFileHints(input) {\n    const NO_FILE_PATTERN = /no file|upload later|after ordering/i;\n    // Walk up the DOM and look for elements whose direct text matches.\n    let walker = input.parentElement;\n    let depth = 0;\n    while (walker && depth < 6) {\n      // Skip if this container is our own UI\n      if (\n        walker.classList &&\n        (walker.classList.contains(\"ai-attach-link__wrap\") ||\n          walker.classList.contains(\"ai-attach-chip\") ||\n          walker.classList.contains(\"ai-attach-mockup\"))\n      ) {\n        walker = walker.parentElement;\n        depth++;\n        continue;\n      }\n      // Walk descendants of this container looking for text-bearing nodes\n      // whose own (direct, not aggregated) text matches.\n      const candidates = walker.querySelectorAll(\"p, span, div, small, em, i\");\n      for (let i = 0; i < candidates.length; i++) {\n        const el = candidates[i];\n        // Skip our own UI\n        if (\n          el.closest(\n            \".ai-attach-link__wrap, .ai-attach-chip, .ai-attach-mockup, .ai-attach-modal\"\n          )\n        ) continue;\n        // Cap aggregated text length to avoid huge ancestor matches\n        if ((el.textContent || \"\").length > 200) continue;\n        if (NO_FILE_PATTERN.test(el.textContent || \"\")) {\n          el.dataset.aiHiddenForDesign = \"1\";\n          el.style.display = \"none\";\n        }\n      }\n      walker = walker.parentElement;\n      depth++;\n    }\n  }\n\n  /** Reverse of hideHostNoFileHints \u2014 bring back anything we hid. */\n  function restoreHostNoFileHints(input) {\n    document\n      .querySelectorAll('[data-ai-hidden-for-design=\"1\"]')\n      .forEach(function (el) {\n        el.style.display = \"\";\n        delete el.dataset.aiHiddenForDesign;\n      });\n  }\n\n  // ============= Live tee mockup preview =============\n\n  /**\n   * Composite the AI design onto the product photo at an appropriate position\n   * for the print location, with the design's black bg chroma-keyed out.\n   *\n   * Picks a different base image for back prints when one is available in\n   * the product gallery (so a \"back print\" doesn't show on the front of\n   * the tee).\n   */\n  async function renderMockup(input, design, wrap) {\n    const mockup = wrap.querySelector(\".ai-attach-mockup\");\n    if (!mockup) return;\n\n    const position = positionForInput(input);\n    const isBack = sideForInput(input) === \"back\";\n    const productUrl = findProductImageForSide(isBack ? \"back\" : \"front\");\n    if (!productUrl) {\n      mockup.hidden = true;\n      return;\n    }\n    // Safety \u2014 if we somehow ended up with the design URL as the \"product\"\n    // image, bail rather than composite it onto itself.\n    if (productUrl === design.draftUrl) {\n      console.warn(\"[ai-design-attach] product image equals design URL, hiding mockup\");\n      mockup.hidden = true;\n      return;\n    }\n\n    mockup.hidden = false;\n    const inner = mockup.querySelector(\".ai-attach-mockup__inner\");\n    inner.innerHTML = '<span class=\"ai-attach-mockup__loading\">Rendering preview\u2026</span>';\n\n    try {\n      const canvas = await composeMockup(productUrl, design.draftUrl, position);\n      inner.innerHTML = \"\";\n      inner.appendChild(canvas);\n    } catch (e) {\n      console.warn(\"Mockup composite failed\", e);\n      inner.innerHTML = '<span class=\"ai-attach-mockup__error\">Couldn\\'t render preview</span>';\n    }\n  }\n\n  /**\n   * Pick the mockup base image URL for the given side (\"front\" or \"back\").\n   *\n   * Reads from window.AIDesignConfig.mockup which is set by the snippet\n   * from theme settings (Customize \u2192 Theme settings \u2192 AI Design Mockups).\n   * Roland uploads one front + one back blank-tee photo via the customizer\n   * and they're used universally for every product on the site \u2014 no\n   * per-product configuration, no fragile auto-detection.\n   *\n   * Returns null if no mockup configured (preview is hidden quietly in that\n   * case, no error shown to the customer).\n   */\n  function findProductImageForSide(side) {\n    const cfg = (window.AIDesignConfig && window.AIDesignConfig.mockup) || {};\n    if (side === \"back\" && cfg.back) return cfg.back;\n    // Use front for any non-back location (chest, sleeve, pocket, default)\n    if (cfg.front) return cfg.front;\n    // Back-only configured but customer attached on front: fall back to back.\n    if (cfg.back) return cfg.back;\n    return null;\n  }\n\n  /**\n   * Determine where on the tee a design at this print location should sit,\n   * in normalized 0..1 coords. We classify by keywords in the input's\n   * name attribute (set up by the merchant's product line item properties).\n   *\n   * Format: { cx, cy, width } \u2014 center x/y as fraction of canvas, design\n   * width as fraction of canvas width.\n   */\n  /**\n   * Coords are in normalized image space (0..1). They reflect typical AS\n   * Colour-style tee photography where the tee occupies ~70% of the frame\n   * height and ~70% of the width, with whitespace around it.\n   *\n   *   Front of tee  \u2192 roughly 12% to 88% of image height\n   *   Back of tee   \u2192 roughly 12% to 88% of image height\n   *   Tee chest area starts ~22% down from top of frame\n   *   Tee shoulder line is at roughly 14% from top of frame\n   */\n  /**\n   * Walk up the DOM from a file input collecting visible text from ancestors,\n   * plus the input's own name/id/aria-label. Used by BOTH side detection\n   * (front vs back) and position detection so they always agree on which\n   * print location this input represents.\n   */\n  function buildInputContext(input) {\n    let ctx =\n      (input.name || \"\") + \" \" +\n      (input.id || \"\") + \" \" +\n      (input.getAttribute(\"aria-label\") || \"\");\n    let walker = input.parentElement;\n    let depth = 0;\n    while (walker && depth < 5) {\n      const t = (walker.textContent || \"\").slice(0, 300);\n      ctx += \" \" + t;\n      walker = walker.parentElement;\n      depth++;\n    }\n    return ctx.toLowerCase();\n  }\n\n  /** Returns \"front\" or \"back\" based on context. */\n  function sideForInput(input) {\n    const ctx = buildInputContext(input);\n    return /\\bback\\b/.test(ctx) ? \"back\" : \"front\";\n  }\n\n  function positionForInput(input) {\n    const ctx = buildInputContext(input);\n\n    const isBack = /\\bback\\b/.test(ctx);\n    const isSleeve = /\\bsleeve\\b/.test(ctx);\n    const isPocket = /\\bpocket\\b/.test(ctx);\n    // \"Large Front\" / \"Full Front\" \u2014 full-chest print (used by the AI promo).\n    // Must be checked BEFORE leftChest because the input id 'pls-large-front'\n    // contains 'front' and we want the large-print branch to win.\n    const isLargeFront = !isBack && /\\blarge\\s*front\\b|\\bfront\\s*large\\b|\\bfull\\s*front\\b|\\bfront\\s*full\\b/.test(ctx);\n    const isLeftChest = !isLargeFront && /\\bleft\\s*(chest|front|breast)\\b|\\bchest\\s*left\\b|\\bleft\\s*pocket\\b|\\bchest\\s*pocket\\b/.test(ctx);\n    const isRightChest = !isLargeFront && /\\bright\\s*(chest|front|breast)\\b|\\bchest\\s*right\\b|\\bright\\s*pocket\\b/.test(ctx);\n    const isCenterChest = !isLeftChest && !isRightChest && !isLargeFront && (/\\bcentre?\\s*chest\\b|\\bchest\\s*centre?\\b|\\bfront\\s*center\\b/.test(ctx));\n\n    // Full back print \u2014 large, centered, slightly above mid\n    if (isBack) return { cx: 0.5, cy: 0.34, width: 0.34 };\n    // Sleeve \u2014 small, on the upper arm area\n    if (isSleeve) return { cx: 0.20, cy: 0.26, width: 0.06 };\n    // Large front print \u2014 full chest, ~A3 size, centred slightly below mid-chest.\n    // Real-world \u2248 30 cm wide sitting ~10 cm below the collar on a tee.\n    if (isLargeFront) return { cx: 0.5, cy: 0.45, width: 0.45 };\n    // Front left chest \u2014 pocket-logo position. In industry terms \"left\" is the\n    // WEARER's left, which on a front-facing tee photo is the image's RIGHT\n    // side (cx > 0.5). ~10\u00D710 cm chest print \u2248 10% of image width.\n    if (isLeftChest) return { cx: 0.60, cy: 0.30, width: 0.10 };\n    // Front right chest \u2014 mirror (appears on image's left side)\n    if (isRightChest) return { cx: 0.40, cy: 0.30, width: 0.10 };\n    // Pocket (no left/right specified) \u2014 assume left pocket position\n    if (isPocket) return { cx: 0.60, cy: 0.32, width: 0.10 };\n    // Centered chest print, mid-size\n    if (isCenterChest) return { cx: 0.5, cy: 0.32, width: 0.22 };\n    // Default: assume centered chest print\n    return { cx: 0.5, cy: 0.32, width: 0.22 };\n  }\n\n  function loadImage(url, crossOrigin) {\n    return new Promise(function (resolve, reject) {\n      const img = new Image();\n      if (crossOrigin) img.crossOrigin = crossOrigin;\n      img.onload = function () { resolve(img); };\n      img.onerror = function () { reject(new Error(\"Couldn't load \" + url)); };\n      img.src = url;\n    });\n  }\n\n  async function composeMockup(productUrl, designUrl, position) {\n    // Load product image WITH crossOrigin=\"anonymous\" so the canvas isn't\n    // tainted. Shopify CDN serves images with Access-Control-Allow-Origin\n    // headers, so this works as long as the requester sets crossOrigin\n    // before the load. Without it, the browser blocks canvas reads\n    // (toBlob, getImageData) for sharing/downloading.\n    //\n    // If the CORS-loaded path fails (e.g. mockup hosted on a server that\n    // doesn't return CORS), fall back to loading without crossOrigin \u2014\n    // the canvas will be tainted but at least the visual preview works.\n    let productImg;\n    let canExportCanvas = true;\n    try {\n      productImg = await loadImage(productUrl, \"anonymous\");\n    } catch (corsErr) {\n      console.warn(\"[mockup] CORS-load failed, falling back to tainted preview:\", corsErr);\n      productImg = await loadImage(productUrl);\n      canExportCanvas = false;\n    }\n\n    // Fetch design as blob (XHR \u2014 bypasses Shopify pixel wrappers, R2 CORS\n    // configured to allow this) then load via object URL so canvas isn't\n    // tainted by cross-origin.\n    const blob = await window.AIDesignFetch.fetchBlob(designUrl);\n    const objectUrl = URL.createObjectURL(blob);\n    const designImg = await loadImage(objectUrl);\n\n    try {\n      // Render at the mockup's full resolution so the chest-sized design\n      // gets enough pixels to look sharp. 1200 matches the width=1200 we\n      // request from Shopify's CDN.\n      const maxW = 1200;\n      const scale = Math.min(1, maxW / productImg.naturalWidth);\n      const cw = Math.round(productImg.naturalWidth * scale);\n      const ch = Math.round(productImg.naturalHeight * scale);\n\n      const canvas = document.createElement(\"canvas\");\n      canvas.width = cw;\n      canvas.height = ch;\n      canvas.className = \"ai-attach-mockup__canvas\";\n      const ctx = canvas.getContext(\"2d\");\n      if (!ctx) throw new Error(\"Canvas not supported\");\n      ctx.imageSmoothingEnabled = true;\n      ctx.imageSmoothingQuality = \"high\";\n\n      // Draw the tee photo as the base\n      ctx.drawImage(productImg, 0, 0, cw, ch);\n\n      // Chroma-key the design's black bg to transparent on a working canvas.\n      // Use a tighter SOFT_RANGE to keep edges crisp without halos.\n      const THRESHOLD = 25;\n      const SOFT_RANGE = 15;\n      const keyedCanvas = document.createElement(\"canvas\");\n      keyedCanvas.width = designImg.naturalWidth;\n      keyedCanvas.height = designImg.naturalHeight;\n      const keyedCtx = keyedCanvas.getContext(\"2d\");\n      keyedCtx.drawImage(designImg, 0, 0);\n      const data = keyedCtx.getImageData(0, 0, keyedCanvas.width, keyedCanvas.height);\n      const px = data.data;\n      for (let i = 0; i < px.length; i += 4) {\n        const r = px[i], g = px[i + 1], b = px[i + 2];\n        const brightness = Math.max(r, g, b);\n        if (brightness < THRESHOLD) {\n          px[i + 3] = 0;\n        } else if (brightness < THRESHOLD + SOFT_RANGE) {\n          const t = (brightness - THRESHOLD) / SOFT_RANGE;\n          px[i + 3] = Math.round(px[i + 3] * t);\n        }\n      }\n      keyedCtx.putImageData(data, 0, 0);\n\n      // Step-down resample the keyed design to the target size. Downscaling\n      // in halves (with smoothing on each step) preserves edge detail much\n      // better than one giant shrink in a single drawImage call.\n      const targetW = Math.round(cw * position.width);\n      const aspect = designImg.naturalHeight / designImg.naturalWidth;\n      const targetH = Math.round(targetW * aspect);\n\n      let stepCanvas = keyedCanvas;\n      while (stepCanvas.width / 2 > targetW * 1.5) {\n        const next = document.createElement(\"canvas\");\n        next.width = Math.round(stepCanvas.width / 2);\n        next.height = Math.round(stepCanvas.height / 2);\n        const nctx = next.getContext(\"2d\");\n        nctx.imageSmoothingEnabled = true;\n        nctx.imageSmoothingQuality = \"high\";\n        nctx.drawImage(stepCanvas, 0, 0, next.width, next.height);\n        stepCanvas = next;\n      }\n\n      // Composite at the right position on the tee\n      const targetX = cw * position.cx - targetW / 2;\n      const targetY = ch * position.cy - targetH / 2;\n      ctx.drawImage(stepCanvas, targetX, targetY, targetW, targetH);\n\n      // \u2500\u2500\u2500 Branded footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      // Adds a dark strip at the bottom of the canvas with marketing\n      // text. Customer's tee photo gets re-purposed as a shareable\n      // social asset that still drives traffic back to the site.\n      drawBrandFooter(ctx, cw, ch);\n\n      // Tag the canvas so callers know whether it's safe to read pixels.\n      // toBlob / getImageData throw SecurityError on tainted canvases,\n      // but adding a property lets the share flow check before it tries.\n      try { canvas.dataset.aiCanExport = canExportCanvas ? \"1\" : \"0\"; } catch (_) {}\n\n      return canvas;\n    } finally {\n      URL.revokeObjectURL(objectUrl);\n    }\n  }\n\n  /**\n   * Draw the \"Made with 60ftink.com.au AI Designer. Get yours Now!\" footer\n   * across the bottom of the mockup canvas. Black background strip with\n   * white text \u2014 survives any social platform's compression and looks\n   * the same on any background.\n   */\n  function drawBrandFooter(ctx, cw, ch) {\n    const stripH = Math.max(60, Math.round(ch * 0.085));\n    const y0 = ch - stripH;\n\n    // Black strip\n    ctx.fillStyle = \"#0f172a\";\n    ctx.fillRect(0, y0, cw, stripH);\n\n    // Subtle yellow accent line at top of strip \u2014 matches site theme color\n    const accentH = Math.max(2, Math.round(stripH * 0.04));\n    ctx.fillStyle = \"#f59e0b\";\n    ctx.fillRect(0, y0, cw, accentH);\n\n    // Text \u2014 white, centered, bold sans-serif. Two lines to fit nicely.\n    const padding = Math.round(stripH * 0.18);\n    const lineGap = Math.round(stripH * 0.06);\n    const baseFontSize = Math.max(14, Math.round(stripH * 0.32));\n    const ctaFontSize = Math.max(16, Math.round(stripH * 0.40));\n\n    ctx.fillStyle = \"#ffffff\";\n    ctx.textAlign = \"center\";\n    ctx.textBaseline = \"middle\";\n\n    // Line 1: small \"Made with 60ftink.com.au AI Designer\"\n    ctx.font = \"600 \" + baseFontSize + \"px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\";\n    const line1Y = y0 + accentH + padding + baseFontSize / 2;\n    ctx.fillText(\"Made with 60ftink.com.au AI Designer\", cw / 2, line1Y);\n\n    // Line 2: bigger CTA \"Get yours Now!\" in yellow\n    ctx.fillStyle = \"#fbbf24\";\n    ctx.font = \"800 \" + ctaFontSize + \"px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\";\n    const line2Y = line1Y + baseFontSize / 2 + lineGap + ctaFontSize / 2;\n    ctx.fillText(\"Get yours Now!\", cw / 2, line2Y);\n  }\n\n  function refreshVisibility() {\n    if (!window.AIDesignLibrary) return;\n    const hasDesigns = window.AIDesignLibrary.list().length > 0;\n    document.querySelectorAll(\".\" + LINK_CLASS + \"__wrap\").forEach(function (el) {\n      el.style.display = hasDesigns ? \"\" : \"none\";\n    });\n  }\n\n  // ============= Modal (reused from prior version) =============\n  function openLibraryModal(opts) {\n    const designs = window.AIDesignLibrary.list();\n    const cfg = window.AIDesignConfig || {};\n    const designerUrl = cfg.designerUrl || \"/pages/design-with-ai\";\n    const myDesignsUrl = cfg.myDesignsUrl || \"/pages/my-designs\";\n\n    const overlay = document.createElement(\"div\");\n    overlay.className = \"ai-attach-modal\";\n\n    const isEmpty = !designs.length;\n\n    overlay.innerHTML = [\n      '<div class=\"ai-attach-modal__sheet\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Pick an AI design\">',\n      '  <header class=\"ai-attach-modal__header\">',\n      '    <h2>Pick a saved design</h2>',\n      '    <button type=\"button\" class=\"ai-attach-modal__close\" data-ai-modal-close aria-label=\"Close\">\u00D7</button>',\n      '  </header>',\n      isEmpty\n        ? [\n            '  <div class=\"ai-attach-modal__empty\">',\n            '    <p>You haven\u2019t designed anything yet.</p>',\n            '    <a class=\"ai-attach-modal__cta\" href=\"' + designerUrl + '\">Create a design</a>',\n            '  </div>',\n          ].join(\"\")\n        : [\n            '  <ul class=\"ai-attach-modal__grid\"></ul>',\n            '  <footer class=\"ai-attach-modal__footer\">',\n            '    <a class=\"ai-attach-modal__link\" href=\"' + designerUrl + '\">+ Make another design</a>',\n            '    <a class=\"ai-attach-modal__link\" href=\"' + myDesignsUrl + '\">Manage all designs \u2192</a>',\n            '  </footer>',\n          ].join(\"\"),\n      '</div>',\n    ].join(\"\");\n\n    if (!isEmpty) {\n      const grid = overlay.querySelector(\".ai-attach-modal__grid\");\n      designs.forEach(function (d) {\n        const tile = document.createElement(\"li\");\n        tile.className = \"ai-attach-modal__tile\";\n        tile.innerHTML = [\n          '<button type=\"button\" class=\"ai-attach-modal__pick\">',\n          '  <div class=\"ai-attach-modal__thumb\">',\n          '    <img alt=\"\" />',\n          '  </div>',\n          '  <span class=\"ai-attach-modal__prompt\"></span>',\n          '</button>',\n        ].join(\"\");\n        const img = tile.querySelector(\"img\");\n        img.src = d.thumbnail || d.draftUrl;\n        img.width = 240;\n        img.height = 240;\n        img.loading = \"lazy\";\n        tile.querySelector(\".ai-attach-modal__prompt\").textContent =\n          d.prompt || \"(no prompt)\";\n        tile.querySelector(\"button\").addEventListener(\"click\", function () {\n          opts.onPick(d);\n          closeModal();\n        });\n        grid.appendChild(tile);\n      });\n    }\n\n    function closeModal() {\n      overlay.remove();\n      document.body.classList.remove(\"ai-attach-modal-open\");\n    }\n\n    overlay.querySelector(\"[data-ai-modal-close]\").addEventListener(\"click\", closeModal);\n    overlay.addEventListener(\"click\", function (e) {\n      if (e.target === overlay) closeModal();\n    });\n    document.addEventListener(\"keydown\", function escHandler(e) {\n      if (e.key === \"Escape\") {\n        closeModal();\n        document.removeEventListener(\"keydown\", escHandler);\n      }\n    });\n\n    document.body.appendChild(overlay);\n    document.body.classList.add(\"ai-attach-modal-open\");\n  }\n\n  // \u2500\u2500\u2500 Public mockup compositor \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Exposed so other scripts (notably ai-inspiration.js for the promo\n  // \"share-to-unlock\" success modal) can build a tee mockup from a design\n  // URL. Wrapped in try/catch so any future change to composeMockup or\n  // its dependencies can't break this module's start() call below.\n  try {\n    window.AIDesignMockup = {\n      composeFront: function (designUrl) {\n        var cfg = (window.AIDesignConfig && window.AIDesignConfig.mockup) || {};\n        var productUrl = cfg.front || cfg.back;\n        if (!productUrl) {\n          return Promise.reject(new Error(\"No mockup base image configured in theme settings\"));\n        }\n        // Standard chest placement \u2014 matches the \"front large chest\"\n        // position used by the live preview on product pages.\n        var position = { cx: 0.5, cy: 0.42, width: 0.30 };\n        return composeMockup(productUrl, designUrl, position);\n      },\n    };\n  } catch (e) {\n    console.warn(\"[ai-design-attach] couldn't expose AIDesignMockup:\", e);\n  }\n\n  // Now that all consts and functions are declared, kick things off.\n  start();\n})();\n"],
  "mappings": "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",
  "names": []
}
