{
  "version": 3,
  "sources": ["/cdn/shop/t/72/assets/bulk-pricing-discount-manager.js?cb=1784840826447"],
  "sourcesContent": ["/**\n * Bulk Pricing Discount Manager\n * Applies Shopify discount codes when every eligible line shares one tier,\n * and renders progress without simulating prices in the browser.\n */\n\nclass BulkPricingDiscountManager {\n  constructor() {\n    this.isProcessing = false;\n    this.isApplyingDiscount = false;\n    this.productEligibilityCache = new Map();\n    this.lastProcessTime = 0;\n    this.processCooldown = 2000; // 2 seconds cooldown between processes\n    this.pendingCartUpdateTimeoutId = null;\n    this.tierRenderTimeoutId = null;\n    this.init();\n  }\n\n  init() {\n    // Listen for cart updates to show tier progress\n    document.addEventListener('cart:updated', this.handleCartUpdate.bind(this));\n    document.addEventListener('cart:refresh', this.handleCartUpdate.bind(this));\n    document.addEventListener('cart:update-display', this.handleCartUpdate.bind(this));\n    \n    // Listen for quantity changes\n    this.initQuantityChangeListeners();\n    \n    // Apply on page load\n    setTimeout(() => this.handleCartUpdate(), 1000);\n    \n    // Show tier progress in mini cart\n    this.initMiniCartTierProgress();\n    \n    // Apply proper bulk pricing discounts\n    this.applyBulkPricingDiscounts();\n\n    // Re-apply tier progress when the cart DOM changes\n    this.observeCartDomChanges();\n    \n    // Intercept cart update errors and show them near specific products\n    this.interceptCartErrors();\n  }\n\n  isCartPage() {\n    const path = window.location.pathname || '';\n    return /(^|\\/)cart(\\/|$)/.test(path);\n  }\n\n  interceptCartErrors() {\n    // 2026-07 (P0 root-cause fix): removed the window.fetch monkey-patch.\n    // It wrapped EVERY cart mutation \u2014 including the theme's own /cart/change.js\n    // quantity updates \u2014 and threw on non-ok responses, which blocked quantity\n    // edits. It also fired the now-retired discount cascade on every mutation.\n    // Patching window.fetch is inherently fragile (kt-cart-page.js deliberately\n    // captures the native fetch to avoid such wrappers). Cart errors surface\n    // through the theme's own handling; we keep only the passive DOM watcher.\n    //\n    // Tier-progress display refreshes via the cart:updated / cart:refresh /\n    // cart:update-display listeners and on page load \u2014 no fetch hook needed now\n    // that this manager performs no cart writes.\n    this.monitorForErrorMessages();\n  }\n\n  monitorForErrorMessages() {\n    // Use MutationObserver to detect when error messages appear\n    const observer = new MutationObserver((mutations) => {\n      mutations.forEach((mutation) => {\n        mutation.addedNodes.forEach((node) => {\n          if (node.nodeType === Node.ELEMENT_NODE) {\n            // Check if this is an error message\n            if (node.classList && (\n              node.classList.contains('t4s-notices__mess') ||\n              node.classList.contains('t4s-cart__errors') ||\n              node.querySelector('.t4s-notices__mess')\n            )) {\n              // Find the error message\n              const errorMessage = node.classList.contains('t4s-notices__mess') \n                ? node \n                : node.querySelector('.t4s-notices__mess');\n              \n              if (errorMessage && errorMessage.textContent.includes('Not enough items available')) {\n                // Move this error message near the last updated product\n                this.moveErrorToProduct(errorMessage);\n              }\n            }\n          }\n        });\n      });\n    });\n    \n    // Start observing\n    observer.observe(document.body, {\n      childList: true,\n      subtree: true\n    });\n  }\n\n  moveErrorToProduct(errorMessage) {\n    // Find the last updated cart item (most recently interacted with)\n    const cartItems = document.querySelectorAll('[data-cart-item]');\n    let targetItem = null;\n    let targetQuantityInput = null;\n    \n    // Try to find the item that was most recently updated\n    for (let item of cartItems) {\n      const quantityInput = item.querySelector('input[type=\"number\"]');\n      if (quantityInput && quantityInput.dataset.lastUpdated) {\n        targetItem = item;\n        targetQuantityInput = quantityInput;\n        break;\n      }\n    }\n    \n    // If no specific item found, use the first cart item\n    if (!targetItem && cartItems.length > 0) {\n      targetItem = cartItems[0];\n      targetQuantityInput = targetItem.querySelector('input[type=\"number\"]');\n    }\n    \n    if (targetItem) {\n      // Remove any existing error messages for this item\n      const existingError = targetItem.querySelector('.product-error-message');\n      if (existingError) {\n        existingError.remove();\n      }\n      \n      // Create a new error message near the product\n      const newErrorDiv = document.createElement('div');\n      newErrorDiv.className = 'product-error-message persistent-error';\n      newErrorDiv.textContent = errorMessage.textContent;\n      newErrorDiv.dataset.itemKey = targetItem.dataset.cartItem || 'unknown';\n      \n      // Insert after the cart item\n      targetItem.insertAdjacentElement('afterend', newErrorDiv);\n      \n      // Set up quantity change listener to remove error when quantity is fixed\n      if (targetQuantityInput) {\n        const removeErrorOnValidQuantity = () => {\n          const currentQuantity = parseInt(targetQuantityInput.value) || 0;\n          // Extract available quantity from error message (e.g., \"Only 17 left\")\n          const availableMatch = errorMessage.textContent.match(/(\\d+)\\s+left/);\n          const availableQuantity = availableMatch ? parseInt(availableMatch[1]) : 0;\n          \n          if (currentQuantity <= availableQuantity && currentQuantity > 0) {\n            // Quantity is now valid, remove the error\n            if (newErrorDiv.parentNode) {\n              newErrorDiv.remove();\n            }\n            // Remove the event listener\n            targetQuantityInput.removeEventListener('change', removeErrorOnValidQuantity);\n            targetQuantityInput.removeEventListener('input', removeErrorOnValidQuantity);\n          }\n        };\n        \n        // Listen for quantity changes\n        targetQuantityInput.addEventListener('change', removeErrorOnValidQuantity);\n        targetQuantityInput.addEventListener('input', removeErrorOnValidQuantity);\n      }\n    }\n    \n    // Hide the original error message\n    errorMessage.style.display = 'none';\n    if (errorMessage.parentNode) {\n      errorMessage.parentNode.style.display = 'none';\n    }\n  }\n\n  showProductSpecificError(errorData, options) {\n    // Remove any existing product-specific error messages\n    document.querySelectorAll('.product-error-message').forEach(msg => msg.remove());\n    \n    // Find the cart item being updated\n    let targetItem = null;\n    \n    if (options && options.body) {\n      try {\n        const bodyData = JSON.parse(options.body);\n        if (bodyData.id) {\n          // Find cart item by variant ID\n          targetItem = document.querySelector(`[data-variant-id=\"${bodyData.id}\"]`);\n        } else if (bodyData.updates) {\n          // Find cart item by key\n          const itemKey = Object.keys(bodyData.updates)[0];\n          targetItem = document.querySelector(`[data-cart-item-key=\"${itemKey}\"]`);\n        }\n      } catch (e) {\n        // Handle form data\n        if (options.body instanceof FormData) {\n          const itemKey = options.body.get('id') || options.body.get('updates[]');\n          if (itemKey) {\n            targetItem = document.querySelector(`[data-variant-id=\"${itemKey}\"]`) || \n                       document.querySelector(`[data-cart-item-key*=\"${itemKey}\"]`);\n          }\n        }\n      }\n    }\n    \n    // If we can't find the specific item, show error at the top\n    if (!targetItem) {\n      targetItem = document.querySelector('.t4s-cartPage__items') || \n                  document.querySelector('[data-cart-items]') ||\n                  document.body;\n    }\n    \n    // Create error message\n    const errorDiv = document.createElement('div');\n    errorDiv.className = 'product-error-message';\n    errorDiv.textContent = errorData.message || 'Not enough items available. Please reduce quantity.';\n    \n    // Insert error message near the product\n    if (targetItem.classList.contains('t4s-page_cart__item')) {\n      // Insert after the cart item\n      targetItem.insertAdjacentElement('afterend', errorDiv);\n    } else {\n      // Insert at the beginning of the container\n      targetItem.insertBefore(errorDiv, targetItem.firstChild);\n    }\n    \n    // Auto-remove after 5 seconds\n    setTimeout(() => {\n      if (errorDiv.parentNode) {\n        errorDiv.remove();\n      }\n    }, 5000);\n  }\n\n  async handleCartUpdate() {\n    // Prevent infinite loops and rate limiting without dropping a real cart\n    // mutation that lands during the cooldown window.\n    const now = Date.now();\n    if (this.isProcessing || (now - this.lastProcessTime) < this.processCooldown) {\n      if (this.pendingCartUpdateTimeoutId) clearTimeout(this.pendingCartUpdateTimeoutId);\n      const remainingCooldown = Math.max(250, this.processCooldown - (now - this.lastProcessTime) + 25);\n      this.pendingCartUpdateTimeoutId = setTimeout(() => {\n        this.pendingCartUpdateTimeoutId = null;\n        this.handleCartUpdate();\n      }, remainingCooldown);\n      return;\n    }\n    \n    this.isProcessing = true;\n    this.lastProcessTime = now;\n    \n    try {\n      // Get current cart\n      const cartResponse = await fetch('/cart.js');\n      const cart = await cartResponse.json();\n      \n      if (cart.items.length === 0) {\n        document.querySelectorAll('.mini-cart-tier-progress').forEach((element) => element.remove());\n        this.isProcessing = false;\n        return;\n      }\n      \n      const eligibleItems = [];\n      for (const item of cart.items) {\n        if (await this.isBulkEligible(item)) eligibleItems.push(item);\n      }\n\n      // Per-line progress belongs only on the cart page. The drawer uses its\n      // dedicated aggregate progress component below.\n      if (this.isCartPage()) this.scheduleTierProgressRender(eligibleItems);\n      else setTimeout(() => this.updateMiniCartTierProgress(), 300);\n      \n      // Apply proper bulk pricing discounts\n      this.applyBulkPricingDiscounts();\n      \n      // Safety re-render after DOM settles (still debounced)\n      if (this.isCartPage()) {\n        setTimeout(() => this.scheduleTierProgressRender(eligibleItems), 400);\n      }\n      \n    } catch (error) {\n      console.error('Error processing tier progress:', error);\n    } finally {\n      this.isProcessing = false;\n    }\n  }\n\n  observeCartDomChanges() {\n    // 2026-07-23 (P0 fix): DISABLED. This used to watch the cart-items\n    // container for childList/subtree mutations and, on ANY mutation, fetch\n    // /cart.js then render per-line tier progress. But showTierProgress()\n    // appends its progress element INTO that same observed container, so the\n    // observer re-fired on its own DOM write \u2192 fetch \u2192 render \u2192 fire \u2026 an\n    // infinite loop that hammered /cart.js (~1 req/sec) and made quantity\n    // edits impossible (the cart re-rendered continuously). The observer was\n    // redundant anyway: real cart mutations already reach handleCartUpdate()\n    // via the cart:updated/cart:refresh/cart:update-display listeners and the\n    // fetch-wrapper success path \u2014 both cooldown-guarded. Kept as a safe\n    // no-op so existing call sites don't break.\n    try {\n      if (this.cartDomObserver && typeof this.cartDomObserver.disconnect === 'function') {\n        this.cartDomObserver.disconnect();\n      }\n    } catch (_) {}\n    this.cartDomObserver = null;\n  }\n\n  scheduleTierProgressRender(cartItems) {\n    try {\n      if (this.tierRenderTimeoutId) {\n        clearTimeout(this.tierRenderTimeoutId);\n        this.tierRenderTimeoutId = null;\n      }\n      // Debounce to prevent flicker and duplicate renders\n      this.tierRenderTimeoutId = setTimeout(() => {\n        this.showTierProgress(cartItems);\n        this.tierRenderTimeoutId = null;\n      }, 180);\n    } catch (_) {}\n  }\n\n  async processItemBulkPricing(item) {\n    const quantity = item.quantity;\n    let discountPercent = 0;\n    \n    // Determine discount based on individual product quantity\n    if (quantity >= 20) {\n      discountPercent = 7;\n    } else if (quantity >= 10) {\n      discountPercent = 5;\n    } else if (quantity >= 5) {\n      discountPercent = 3;\n    } else if (quantity >= 2) {\n      discountPercent = 2;\n    }\n    \n    \n    // Note: Bulk pricing is now handled by Liquid templates in cart-item.liquid\n    // The JavaScript manager now only handles tier progress display\n    this.showTierProgress([item]);\n  }\n\n  // KT-225: `applyDiscountCode()` and `refreshCart()` were DELETED here. Do not restore\n  // them, and do not add a caller for anything like them.\n  //\n  // Both were already unreachable \u2014 nothing called applyDiscountCode, and refreshCart was\n  // reachable only from it \u2014 so this removes no behaviour. They are gone because they were\n  // a re-armed loop waiting for one call site:\n  //\n  //   refreshCart() dispatched `cart:update-display`\n  //   ...and this class LISTENS to `cart:update-display` -> handleCartUpdate (see the\n  //      constructor), which is what used to call back down into the discount path.\n  //\n  // That is the same cycle the 2026-07-23 P0 fixed, with window.location.reload() swapped\n  // for a self-dispatched event: handleCartUpdate -> applyBulkPricingDiscounts -> (code\n  // never applied) -> refreshCart -> re-enter handleCartUpdate, every 1-2 seconds. The\n  // reload was removed; the cycle was left one function call from returning.\n  //\n  // Their presence had a second cost. Three separate reviews have pointed at this file as\n  // the cause of a \"cart keeps refreshing\" report, because it contains discount code that\n  // mentions refreshing. Each time the answer was that the code is unreachable. Deleting it\n  // ends that: multi-buy is owned by the kt-quantity-breaks Shopify Function and this file\n  // is DISPLAY-ONLY, with no cart writes at all (#370-#373).\n\n  showTierProgress(cartItems) {\n    // Define bulk pricing tiers\n    const tiers = [\n      { min: 2, discount: 2, name: '2% Discount' },\n      { min: 5, discount: 3, name: '3% Discount' },\n      { min: 10, discount: 5, name: '5% Discount' },\n      { min: 20, discount: 7, name: '7% Discount' }\n    ];\n\n    cartItems.forEach(item => {\n      const currentQuantity = item.quantity;\n      const currentTier = this.getCurrentTier(currentQuantity, tiers);\n      const nextTier = this.getNextTier(currentQuantity, tiers);\n      \n      if (nextTier) {\n        const itemsNeeded = nextTier.min - currentQuantity;\n        this.displayTierProgress(item, currentTier, nextTier, itemsNeeded);\n      }\n    });\n  }\n\n  getCurrentTier(quantity, tiers) {\n    for (let i = tiers.length - 1; i >= 0; i--) {\n      if (quantity >= tiers[i].min) {\n        return tiers[i];\n      }\n    }\n    return null;\n  }\n\n  getNextTier(quantity, tiers) {\n    for (const tier of tiers) {\n      if (quantity < tier.min) {\n        return tier;\n      }\n    }\n    return null; // Already at highest tier\n  }\n\n  displayTierProgress(item, currentTier, nextTier, itemsNeeded) {\n    // Find the cart item element\n    const cartItemElement = this.findCartItemElement(item);\n    if (!cartItemElement) return;\n\n    // Determine progress state\n    const progressPercentage = nextTier ? Math.min((item.quantity / nextTier.min) * 100, 100) : 100;\n    const isCloseToTier = nextTier ? (itemsNeeded <= 2) : false;\n    const isAtTier = nextTier ? (itemsNeeded === 0) : true;\n\n    // Update in place if exists to avoid flicker\n    let progressMessage = cartItemElement.querySelector('.tier-progress-message');\n    if (progressMessage) {\n      progressMessage.className = `tier-progress-message ${isCloseToTier ? 'tier-close' : ''} ${isAtTier ? 'tier-reached' : ''}`;\n      progressMessage.setAttribute('data-tier', nextTier ? nextTier.discount : '');\n      progressMessage.setAttribute('data-item-key', item.key);\n\n      const currentTierSpan = progressMessage.querySelector('.current-tier');\n      const nextTierSpan = progressMessage.querySelector('.next-tier');\n      const progressFill = progressMessage.querySelector('.tier-progress-fill');\n      if (currentTierSpan) currentTierSpan.textContent = currentTier ? `Current: ${currentTier.name}` : 'No discount yet';\n      if (nextTierSpan) {\n        nextTierSpan.textContent = nextTier ? (isAtTier ? '\uD83C\uDF89 Tier reached!' : `Add ${itemsNeeded} more for ${nextTier.name}`) : '';\n        if (nextTier && !isAtTier) {\n          nextTierSpan.classList.add('disabled');\n          nextTierSpan.setAttribute('aria-disabled', 'true');\n        } else {\n          nextTierSpan.classList.remove('disabled');\n          nextTierSpan.removeAttribute('aria-disabled');\n        }\n      }\n      if (progressFill) progressFill.style.width = `${progressPercentage}%`;\n      return;\n    }\n\n    // Create if not exists\n    progressMessage = document.createElement('div');\n    progressMessage.className = `tier-progress-message ${isCloseToTier ? 'tier-close' : ''} ${isAtTier ? 'tier-reached' : ''}`;\n    progressMessage.setAttribute('data-tier', nextTier ? nextTier.discount : '');\n    progressMessage.setAttribute('data-item-key', item.key);\n    \n    progressMessage.innerHTML = `\n      <div class=\"tier-progress-container\">\n        <div class=\"tier-progress-info\">\n          <span class=\"current-tier\">${currentTier ? `Current: ${currentTier.name}` : 'No discount yet'}</span>\n          <span class=\"next-tier ${nextTier && !isAtTier ? 'disabled' : ''}\" ${nextTier && !isAtTier ? 'aria-disabled=\"true\"' : ''}>${nextTier ? (isAtTier ? '\uD83C\uDF89 Tier reached!' : `Add ${itemsNeeded} more for ${nextTier.name}`) : ''}</span>\n        </div>\n        <div class=\"tier-progress-bar\">\n          <div class=\"tier-progress-fill\" style=\"width: ${progressPercentage}%\"></div>\n        </div>\n      </div>\n    `;\n\n    // Insert after the item info\n    const itemInfo = cartItemElement.querySelector('.t4s-page_cart__info') || \n                     cartItemElement.querySelector('.t4s-cart-item-info') ||\n                     cartItemElement.querySelector('[class*=\"cart-item\"]');\n    \n    if (itemInfo) {\n      itemInfo.appendChild(progressMessage);\n    } else {\n      // Fallback: append to the cart item itself\n      cartItemElement.appendChild(progressMessage);\n    }\n\n  }\n\n  updateProgressBar(itemKey, newQuantity) {\n    // Find the progress bar for this item\n    const progressMessage = document.querySelector(`[data-item-key=\"${itemKey}\"]`);\n    if (!progressMessage) return;\n\n    // Calculate new tier information\n    const tiers = [\n      { min: 2, discount: 2, name: '2% Discount' },\n      { min: 5, discount: 3, name: '3% Discount' },\n      { min: 10, discount: 5, name: '5% Discount' },\n      { min: 20, discount: 7, name: '7% Discount' }\n    ];\n\n    const currentTier = this.getCurrentTier(newQuantity, tiers);\n    const nextTier = this.getNextTier(newQuantity, tiers);\n    \n    if (nextTier) {\n      const itemsNeeded = nextTier.min - newQuantity;\n      const progressPercentage = Math.min((newQuantity / nextTier.min) * 100, 100);\n      const isCloseToTier = itemsNeeded <= 2;\n      const isAtTier = itemsNeeded === 0;\n\n      // Update the progress bar\n      const progressFill = progressMessage.querySelector('.tier-progress-fill');\n      const currentTierSpan = progressMessage.querySelector('.current-tier');\n      const nextTierSpan = progressMessage.querySelector('.next-tier');\n\n      if (progressFill) {\n        progressFill.style.width = `${progressPercentage}%`;\n      }\n\n      if (currentTierSpan) {\n        currentTierSpan.textContent = currentTier ? `Current: ${currentTier.name}` : 'No discount yet';\n      }\n\n      if (nextTierSpan) {\n        nextTierSpan.textContent = isAtTier ? '\uD83C\uDF89 Tier reached!' : `Add ${itemsNeeded} more for ${nextTier.name}`;\n      }\n\n      // Update classes\n      progressMessage.className = `tier-progress-message ${isCloseToTier ? 'tier-close' : ''} ${isAtTier ? 'tier-reached' : ''}`;\n      progressMessage.setAttribute('data-tier', nextTier.discount);\n\n    }\n\n    // Also update the bulk pricing display for this item\n    this.updateBulkPricingForQuantity(itemKey, newQuantity);\n  }\n\n  findCartItemElement(item) {\n    // Try different selectors to find the cart item element\n    const selectors = [\n      `[data-cart-item-key=\"${item.key}\"]`,\n      `[data-variant-id=\"${item.variant_id}\"]`,\n      `.t4s-page_cart__item:has([href*=\"${item.handle}\"])`,\n      `.cart-item:has([href*=\"${item.handle}\"])`\n    ];\n\n    for (const selector of selectors) {\n      const element = document.querySelector(selector);\n      if (element) return element;\n    }\n\n    // Fallback: find by product title\n    const allCartItems = document.querySelectorAll('.t4s-page_cart__item, .cart-item, [class*=\"cart-item\"]');\n    for (const cartItem of allCartItems) {\n      if (cartItem.textContent.includes(item.title)) {\n        return cartItem;\n      }\n    }\n\n    return null;\n  }\n\n  initMiniCartTierProgress() {\n    // Listen for mini cart updates\n    document.addEventListener('cart:updated', () => {\n      setTimeout(() => this.updateMiniCartTierProgress(), 500);\n    });\n    \n    document.addEventListener('cart:refresh', () => {\n      setTimeout(() => this.updateMiniCartTierProgress(), 500);\n    });\n    \n    // Listen for mini cart opening to refresh tier progress\n    const miniCartObserver = new MutationObserver((mutations) => {\n      mutations.forEach((mutation) => {\n        if (mutation.type === 'attributes') {\n          const miniCart = mutation.target;\n          if (miniCart.classList.contains('is-active') || miniCart.getAttribute('aria-hidden') === 'false') {\n            // Mini cart just opened, update tier progress\n            setTimeout(() => this.updateMiniCartTierProgress(), 300);\n          }\n        }\n      });\n    });\n    \n    // Observe mini cart element for class changes\n    const miniCart = document.querySelector('#t4s-mini_cart, [data-mini-cart]');\n    if (miniCart) {\n      miniCartObserver.observe(miniCart, {\n        attributes: true,\n        attributeFilter: ['class', 'aria-hidden']\n      });\n    }\n    \n    // Initial mini cart tier progress\n    setTimeout(() => this.updateMiniCartTierProgress(), 1500);\n  }\n\n  async updateMiniCartTierProgress() {\n    try {\n      const cartResponse = await fetch('/cart.js');\n      const cart = await cartResponse.json();\n      \n      if (cart.items.length === 0) {\n        // Remove tier progress if cart is empty\n        const miniCart = document.querySelector('#t4s-mini_cart, .mini-cart, [class*=\"mini-cart\"], [data-mini-cart]');\n        if (miniCart) {\n          const existingProgress = miniCart.querySelector('.mini-cart-tier-progress');\n          if (existingProgress) {\n            existingProgress.remove();\n          }\n        }\n        return;\n      }\n      \n      // Find mini cart element\n      const miniCart = document.querySelector('#t4s-mini_cart, .mini-cart, [class*=\"mini-cart\"], [data-mini-cart]');\n      if (!miniCart) return;\n      \n      const eligibleItems = [];\n      for (const item of cart.items) {\n        if (await this.isBulkEligible(item)) eligibleItems.push(item);\n      }\n\n      // Calculate overall tier progress for products that actually participate.\n      const tierProgress = this.calculateOverallTierProgress(eligibleItems);\n      \n      // Check if tier progress element already exists\n      const existingProgress = miniCart.querySelector('.mini-cart-tier-progress');\n      \n      if (tierProgress) {\n        if (existingProgress) {\n          // Update existing element in place\n          this.updateMiniCartTierProgressElement(existingProgress, tierProgress);\n        } else {\n          // Create new element\n          this.displayMiniCartTierProgress(miniCart, tierProgress);\n        }\n      } else {\n        // No tier progress needed, remove if exists\n        if (existingProgress) {\n          existingProgress.remove();\n        }\n      }\n      \n    } catch (error) {\n      console.error('Error updating mini cart tier progress:', error);\n    }\n  }\n\n  calculateOverallTierProgress(cartItems) {\n    const tiers = [\n      { min: 2, discount: 2, name: '2% Discount' },\n      { min: 5, discount: 3, name: '3% Discount' },\n      { min: 10, discount: 5, name: '5% Discount' },\n      { min: 20, discount: 7, name: '7% Discount' }\n    ];\n\n    // Find the item closest to the next tier\n    let closestItem = null;\n    let closestNextTier = null;\n    let minItemsNeeded = Infinity;\n\n    cartItems.forEach(item => {\n      const currentTier = this.getCurrentTier(item.quantity, tiers);\n      const nextTier = this.getNextTier(item.quantity, tiers);\n      \n      if (nextTier) {\n        const itemsNeeded = nextTier.min - item.quantity;\n        if (itemsNeeded < minItemsNeeded) {\n          minItemsNeeded = itemsNeeded;\n          closestItem = item;\n          closestNextTier = nextTier;\n        }\n      }\n    });\n\n    if (closestItem && closestNextTier) {\n      return {\n        item: closestItem,\n        nextTier: closestNextTier,\n        itemsNeeded: minItemsNeeded,\n        progressPercentage: Math.min((closestItem.quantity / closestNextTier.min) * 100, 100)\n      };\n    }\n\n    return null;\n  }\n\n  updateMiniCartTierProgressElement(existingElement, tierProgress) {\n    const { item, nextTier, itemsNeeded, progressPercentage } = tierProgress;\n    const isCloseToTier = itemsNeeded <= 2;\n    const isAtTier = itemsNeeded === 0;\n\n    // Update classes\n    existingElement.className = `mini-cart-tier-progress ${isCloseToTier ? 'tier-close' : ''} ${isAtTier ? 'tier-reached' : ''}`;\n    existingElement.setAttribute('data-tier', nextTier.discount);\n    \n    // Update message\n    const messageElement = existingElement.querySelector('.mini-cart-tier-message');\n    if (messageElement) {\n      messageElement.textContent = isAtTier ? '\uD83C\uDF89 Multi-buy tier reached!' : `Add ${itemsNeeded} more for ${nextTier.discount}% off this item`;\n    }\n    \n    // Update progress bar\n    const progressFill = existingElement.querySelector('.mini-cart-tier-fill');\n    if (progressFill) {\n      progressFill.style.width = `${progressPercentage}%`;\n    }\n  }\n\n  displayMiniCartTierProgress(miniCart, tierProgress) {\n    const { item, nextTier, itemsNeeded, progressPercentage } = tierProgress;\n    const isCloseToTier = itemsNeeded <= 2;\n    const isAtTier = itemsNeeded === 0;\n\n    const progressElement = document.createElement('div');\n    progressElement.className = `mini-cart-tier-progress ${isCloseToTier ? 'tier-close' : ''} ${isAtTier ? 'tier-reached' : ''}`;\n    progressElement.setAttribute('data-tier', nextTier.discount);\n    \n    progressElement.innerHTML = `\n      <div class=\"mini-cart-tier-container\">\n        <div class=\"mini-cart-tier-info\">\n          <span class=\"mini-cart-tier-title\">Multi-buy saving</span>\n          <span class=\"mini-cart-tier-message\">${isAtTier ? '\uD83C\uDF89 Multi-buy tier reached!' : `Add ${itemsNeeded} more for ${nextTier.discount}% off this item`}</span>\n        </div>\n        <div class=\"mini-cart-tier-bar\">\n          <div class=\"mini-cart-tier-fill\" style=\"width: ${progressPercentage}%\"></div>\n        </div>\n      </div>\n    `;\n\n    // Add mini cart specific styles\n    progressElement.style.cssText = `\n      margin: 10px 0;\n      padding: 8px 12px;\n      background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n      border: 1px solid #dee2e6;\n      border-radius: 6px;\n      font-size: 11px;\n      color: #495057;\n      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n    `;\n\n    // Insert into mini cart - try multiple selectors to find the right location\n    const cartItems = miniCart.querySelector('.t4s-mini_cart__items, .mini-cart-items, .kt-mini-cart__items, [class*=\"cart-items\"]');\n    const cartFooter = miniCart.querySelector('.t4s-drawer__bottom, .mini-cart-footer, .kt-mini-cart__footer, [class*=\"cart-footer\"], [class*=\"mini-cart__footer\"]');\n    \n    if (cartFooter) {\n      cartFooter.insertBefore(progressElement, cartFooter.firstChild);\n    } else if (cartItems) {\n      cartItems.appendChild(progressElement);\n    } else {\n      // Fallback: try to find content area\n      const contentArea = miniCart.querySelector('.kt-mini-cart__content, [class*=\"content\"]');\n      if (contentArea) {\n        contentArea.appendChild(progressElement);\n      } else {\n        miniCart.appendChild(progressElement);\n      }\n    }\n\n  }\n\n  updateCartItemDisplay(item, discountPercent) {\n    // Find the cart item element\n    const cartItemElement = this.findCartItemElement(item);\n    if (!cartItemElement) return;\n\n    // Note: Bulk pricing display is now handled by Liquid templates\n    // This method is kept for compatibility but no longer updates pricing\n  }\n\n  updateBulkPricingDisplay(cartItemElement, item, discountPercent) {\n    // Note: Bulk pricing display is now handled entirely by Liquid templates\n    // This method is kept for compatibility but no longer creates display elements\n  }\n\n  updateBulkPricingForQuantity(itemKey, newQuantity) {\n    // Note: Bulk pricing is now handled entirely by Liquid templates\n    // This method is kept for compatibility but no longer updates display\n  }\n\n  removeOldBulkPricing(cartItemElement) {\n    // Remove only cart-related bulk pricing elements from this specific cart item\n    const selectors = [\n      '.bulk-pricing-display',\n      '.t4s-bulk-discount-badge',\n      '[class*=\"discount-badge\"]',\n      '.t4s-cart_discount_price',\n      '.t4s-order-discount__item'\n    ];\n\n    selectors.forEach(selector => {\n      const elements = cartItemElement.querySelectorAll(selector);\n      elements.forEach(element => {\n        // Only remove if it's a cart-related bulk pricing element\n        // Don't remove product page bulk pricing containers\n        if ((element.textContent.includes('Bulk Pricing') || \n            element.textContent.includes('Bulk Discount') ||\n            element.classList.contains('bulk-pricing-display')) &&\n            !element.closest('.t4s-product__bulk-pricing') &&\n            !element.closest('.bulk-pricing-container')) {\n          element.remove();\n        }\n      });\n    });\n  }\n\n  findCartItemElementByKey(itemKey) {\n    // Try different selectors to find the cart item element by key\n    const selectors = [\n      `[data-cart-item-key=\"${itemKey}\"]`,\n      `[data-id=\"${itemKey}\"]`,\n      `[id*=\"${itemKey}\"]`\n    ];\n\n    for (const selector of selectors) {\n      const element = document.querySelector(selector);\n      if (element) return element;\n    }\n\n    // Fallback: find by looking for the item key in the element\n    const allCartItems = document.querySelectorAll('.t4s-page_cart__item, .cart-item, [class*=\"cart-item\"]');\n    for (const cartItem of allCartItems) {\n      if (cartItem.getAttribute('data-cart-item-key') === itemKey ||\n          cartItem.getAttribute('data-id') === itemKey) {\n        return cartItem;\n      }\n    }\n\n    return null;\n  }\n\n  formatMoney(amount) {\n    // Format money amount - amount is already in pounds, not pence\n    return `\u00A3${amount.toFixed(2)}`;\n  }\n\n  async applyBulkPricingDiscounts() {\n    // 2026-07 (P0 root-cause fix): RETIRED. Multi-buy pricing is now owned by\n    // the kt-quantity-breaks Shopify Function (extensions/kt-quantity-breaks),\n    // which discounts each line server-side (2+/5+/10+/20+ -> 2/3/5/7%),\n    // handles mixed-tier carts, and is rendered by main-cart.liquid via\n    // line_level_discount_allocations.\n    //\n    // This legacy path applied cart-level BULK*PERCENT codes by POSTing\n    // /cart/update.js and then re-dispatching `cart:refresh` \u2014 an event this\n    // same manager listens to (handleCartUpdate). Because a cart-level code\n    // cannot price a mixed/product-scoped cart, `appliedBulk` never matched the\n    // desired code, so it re-applied forever: the continuous cart refresh and\n    // the \"can't change quantity\" lock reported across #370-#373. (Its\n    // Function stand-down check was also dead: it looked for an allocation\n    // titled 'Multi-buy savings', but the Function emits 'Multi-buy N% off'.)\n    //\n    // The manager is now DISPLAY-ONLY (tier-progress hints). It performs no\n    // cart mutations. Do not re-enable without deleting the cart-write +\n    // self-dispatch re-entry entirely.\n    return;\n  }\n\n  getTierCode(quantity) {\n    if (quantity >= 20) return 'BULK7PERCENT';\n    if (quantity >= 10) return 'BULK5PERCENT';\n    if (quantity >= 5) return 'BULK3PERCENT';\n    if (quantity >= 2) return 'BULK2PERCENT';\n    return null;\n  }\n\n  async isBulkEligible(item) {\n    const knownBrands = ['British General', 'Masterplug', 'Luceco'];\n    if (knownBrands.includes(item.vendor)) return true;\n\n    const handle = item.handle;\n    if (!handle) return false;\n    if (this.productEligibilityCache.has(handle)) {\n      return this.productEligibilityCache.get(handle);\n    }\n\n    try {\n      const response = await fetch(`/products/${encodeURIComponent(handle)}.js`);\n      if (!response.ok) return false;\n      const product = await response.json();\n      const eligible = knownBrands.includes(product.vendor) ||\n        (product.tags || []).some(tag => knownBrands.includes(tag));\n      this.productEligibilityCache.set(handle, eligible);\n      return eligible;\n    } catch (_) {\n      return false;\n    }\n  }\n\n  async getDesiredBulkCode(cartItems) {\n    const eligibleLines = [];\n    for (const item of cartItems) {\n      if (await this.isBulkEligible(item)) eligibleLines.push(item);\n    }\n\n    if (!eligibleLines.length) return null;\n    const codes = eligibleLines.map(item => this.getTierCode(item.quantity || 0));\n    if (codes.some(code => !code)) return null;\n    const uniqueCodes = Array.from(new Set(codes));\n    return uniqueCodes.length === 1 ? uniqueCodes[0] : null;\n  }\n\n  async updateCartDiscounts(_codes) {\n    // 2026-07 (P0 root-cause fix): RETIRED with applyBulkPricingDiscounts.\n    // This POSTed /cart/update.js (mutating the cart) and re-dispatched\n    // `cart:refresh` into this manager's own listener \u2014 the re-entry that\n    // caused the continuous cart refresh + quantity lock. Multi-buy pricing is\n    // handled by the kt-quantity-breaks Shopify Function. No-op by design.\n    return null;\n  }\n\n  cleanupOldBulkPricing() {\n    // Remove only cart-related bulk pricing elements, not product page bulk pricing\n    const selectors = [\n      '.bulk-pricing-display',\n      '.t4s-bulk-discount-badge',\n      '[class*=\"discount-badge\"]'\n    ];\n\n    selectors.forEach(selector => {\n      const elements = document.querySelectorAll(selector);\n      elements.forEach(element => {\n        // Only remove if it's a cart-related bulk pricing element\n        // Don't remove product page bulk pricing containers\n        if ((element.textContent.includes('Bulk Pricing') || \n            element.textContent.includes('Bulk Discount') ||\n            element.classList.contains('bulk-pricing-display')) &&\n            !element.closest('.t4s-product__bulk-pricing') &&\n            !element.closest('.bulk-pricing-container')) {\n          element.remove();\n        }\n      });\n    });\n\n  }\n\n  initQuantityChangeListeners() {\n    // Listen for quantity input changes\n    document.addEventListener('change', (e) => {\n      if (e.target.matches('input[data-quantity-value], input[name=\"updates[]\"], input[type=\"number\"][min]')) {\n        // Mark this input as recently updated\n        e.target.dataset.lastUpdated = Date.now();\n        \n        const newQuantity = parseInt(e.target.value) || 1;\n        const itemKey = e.target.getAttribute('data-id') || e.target.getAttribute('id');\n        \n        if (itemKey) {\n          this.updateProgressBar(itemKey, newQuantity);\n        }\n        \n        // Also trigger full cart update for comprehensive updates\n        setTimeout(() => this.handleCartUpdate(), 100);\n      }\n    });\n\n    // Listen for quantity button clicks\n    document.addEventListener('click', (e) => {\n      const quantityButton = e.target.closest('[data-quantity-selector], [data-increase-qty], [data-decrease-qty]');\n      if (quantityButton) {\n        // Mark the associated input as recently updated\n        const quantityInput = e.target.closest('[data-cart-item]')?.querySelector('input[type=\"number\"]');\n        if (quantityInput) {\n          quantityInput.dataset.lastUpdated = Date.now();\n        }\n        \n        // Get the associated input field\n        const button = quantityButton;\n        const input = button.closest('.t4s-quantity-wrapper, .quantity-wrapper')?.querySelector('input[type=\"number\"]');\n        \n        if (input) {\n          const itemKey = input.getAttribute('data-id') || input.getAttribute('id');\n          const currentQuantity = parseInt(input.value) || 1;\n          \n          // Predict the new quantity based on button type\n          let newQuantity = currentQuantity;\n          if (button.matches('[data-increase-qty], .is--plus')) {\n            newQuantity = currentQuantity + 1;\n          } else if (button.matches('[data-decrease-qty], .is--minus')) {\n            newQuantity = Math.max(1, currentQuantity - 1);\n          }\n          \n          if (itemKey && newQuantity !== currentQuantity) {\n            // Update immediately for better UX\n            this.updateProgressBar(itemKey, newQuantity);\n          }\n        }\n        \n        // Also trigger full cart update\n        setTimeout(() => this.handleCartUpdate(), 200);\n      }\n    });\n\n    // Listen for cart form submissions\n    document.addEventListener('submit', (e) => {\n      if (e.target.matches('form[action*=\"/cart\"], form[data-cart-form]')) {\n        setTimeout(() => this.handleCartUpdate(), 500);\n      }\n    });\n\n    // Listen for input events (real-time updates)\n    document.addEventListener('input', (e) => {\n      if (e.target.matches('input[data-quantity-value], input[name=\"updates[]\"], input[type=\"number\"][min]')) {\n        const newQuantity = parseInt(e.target.value) || 1;\n        const itemKey = e.target.getAttribute('data-id') || e.target.getAttribute('id');\n        \n        if (itemKey && newQuantity > 0) {\n          // Update progress bar in real-time as user types\n          this.updateProgressBar(itemKey, newQuantity);\n        }\n      }\n    });\n  }\n}\n\n// Prevent multiple instances\nif (!window.bulkPricingManager) {\n// Initialize when DOM is ready\ndocument.addEventListener('DOMContentLoaded', function() {\n    if (!window.bulkPricingManager) {\n      window.bulkPricingManager = new BulkPricingDiscountManager();\n    }\n});\n\n// Also initialize if DOM is already loaded\nif (document.readyState === 'loading') {\n  document.addEventListener('DOMContentLoaded', function() {\n      if (!window.bulkPricingManager) {\n        window.bulkPricingManager = new BulkPricingDiscountManager();\n      }\n  });\n} else {\n    window.bulkPricingManager = new BulkPricingDiscountManager();\n  }\n}\n"],
  "mappings": "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",
  "names": ["miniCart", "existingProgress"]
}
