{
  "version": 3,
  "sources": ["/cdn/shop/t/475/compiled_assets/snippet-scripts.js?cb=7336"],
  "sourcesContent": ["(function() {\n  var __snippets__ = {};\n  (function() {\n    var element = document.getElementById(\"snippets-script\");\n    var attribute = element ? element.getAttribute(\"data-snippets\") : '';\n    var snippets = attribute.split(\",\").filter(Boolean);\n\n    for (var i = 0; i < snippets.length; i++) {\n      __snippets__[snippets[i]] = true;\n    }\n  })();\n  (function() {\n  if (!__snippets__[\"callout-card\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.customElements && customElements.get('callout-shoppable')) return;\n\n    class CalloutShoppable extends HTMLElement {\n      connectedCallback() {\n        if (this.__init) return;\n        this.__init = true;\n\n        this.markers = Array.prototype.slice.call(this.querySelectorAll('[data-callout-hotspot]'));\n        this.overlays = Array.prototype.slice.call(this.querySelectorAll('[data-callout-panel]'));\n\n        this.markers.forEach(function (marker) {\n          marker.addEventListener('click', this.onMarkerClick.bind(this));\n        }, this);\n\n        this.setupPulseSync();\n\n        this.onDocClick = this.onDocClick.bind(this);\n        this.onKeydown = this.onKeydown.bind(this);\n        document.addEventListener('click', this.onDocClick);\n        document.addEventListener('keydown', this.onKeydown);\n\n        this.addEventListener('shopify:block:select', function (e) {\n          var marker = e.target && e.target.closest ? e.target.closest('[data-callout-hotspot]') : null;\n          if (marker) this.open(marker.getAttribute('data-callout-hotspot'));\n        }.bind(this));\n      }\n\n      // Hovering / focusing / opening a marker settles its pulse (and wave) via\n      // `animation: none`, which restarts them from time 0 when released and\n      // drifts out of step with the other markers. After the engaged state ends\n      // we snap the freshly re-created animations back onto the markers' shared\n      // start time so they line up again. (Requires the Web Animations API.)\n      setupPulseSync() {\n        var self = this;\n        this.pulseMarkers = [];\n        this.markers.forEach(function (marker) {\n          if (!marker.getAnimations) return;\n          self.pulseMarkers.push(marker);\n          var resync = function () {\n            requestAnimationFrame(function () { self.syncMarker(marker); });\n          };\n          marker.addEventListener('mouseleave', resync);\n          marker.addEventListener('blur', resync, true);\n        });\n      }\n\n      // The marker's dot pulse plus its wave pseudo-element, when present.\n      markerAnimations(marker) {\n        try { return marker.getAnimations({ subtree: true }); }\n        catch (e) { return marker.getAnimations(); }\n      }\n\n      pulseOrigin() {\n        if (this._pulseOrigin != null) return this._pulseOrigin;\n        for (var i = 0; i < this.pulseMarkers.length; i++) {\n          var anims = this.markerAnimations(this.pulseMarkers[i]);\n          for (var j = 0; j < anims.length; j++) {\n            if (anims[j].startTime != null) { this._pulseOrigin = anims[j].startTime; return this._pulseOrigin; }\n          }\n        }\n        return this._pulseOrigin;\n      }\n\n      syncMarker(marker) {\n        var origin = this.pulseOrigin();\n        if (origin == null) return;\n        this.markerAnimations(marker).forEach(function (a) {\n          try { a.startTime = origin; } catch (e) {}\n        });\n      }\n\n      syncAllMarkers() {\n        var self = this;\n        if (!this.pulseMarkers) return;\n        requestAnimationFrame(function () {\n          self.pulseMarkers.forEach(function (m) { self.syncMarker(m); });\n        });\n      }\n\n      disconnectedCallback() {\n        document.removeEventListener('click', this.onDocClick);\n        document.removeEventListener('keydown', this.onKeydown);\n      }\n\n      overlayFor(id) {\n        for (var i = 0; i < this.overlays.length; i++) {\n          if (this.overlays[i].getAttribute('data-callout-panel') === id) return this.overlays[i];\n        }\n        return null;\n      }\n\n      open(id) {\n        this.markers.forEach(function (m) {\n          m.setAttribute('aria-expanded', m.getAttribute('data-callout-hotspot') === id ? 'true' : 'false');\n        });\n        this.overlays.forEach(function (o) {\n          o.classList.toggle('is-open', o.getAttribute('data-callout-panel') === id);\n        });\n      }\n\n      close() {\n        this.markers.forEach(function (m) { m.setAttribute('aria-expanded', 'false'); });\n        this.overlays.forEach(function (o) { o.classList.remove('is-open'); });\n        this.syncAllMarkers();\n      }\n\n      onMarkerClick(e) {\n        var marker = e.currentTarget;\n        var id = marker.getAttribute('data-callout-hotspot');\n        if (!this.overlayFor(id)) return;\n        if (marker.getAttribute('aria-expanded') === 'true') {\n          this.close();\n        } else {\n          this.open(id);\n        }\n      }\n\n      onDocClick(e) {\n        var marker = e.target.closest ? e.target.closest('[data-callout-hotspot]') : null;\n        if (marker && this.contains(marker)) return;\n        var panel = e.target.closest ? e.target.closest('[data-callout-panel]') : null;\n        if (panel && this.contains(panel)) return;\n        this.close();\n      }\n\n      onKeydown(e) {\n        if (e.key === 'Escape' || e.key === 'Esc') this.close();\n      }\n    }\n\n    if (window.customElements && !customElements.get('callout-shoppable')) {\n      customElements.define('callout-shoppable', CalloutShoppable);\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"cart-eta-data\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    // Last value this page POSTed, so repeated syncs after a drawer refresh\n    // that changed nothing relevant stay silent.\n    var posted = null;\n\n    function sync() {\n      var el = document.querySelector('[data-cart-eta-data]');\n      if (!el) return;\n\n      var payload;\n      try {\n        payload = JSON.parse(el.textContent || '{}');\n      } catch (e) {\n        return;\n      }\n\n      // Round-tripping through the parser normalises the whitespace Liquid\n      // leaves behind, so a value we wrote compares equal on the next render.\n      // Key ORDER survives: variant ids are past 2^32-1, so they are not array\n      // index keys and the object keeps insertion order - cart line order here,\n      // which is what the legacy DOM order was too (it matched the line order on\n      // 61 of 76 multi-line orders sampled; legacy's own order moved about, so\n      // nothing downstream can be relying on it).\n      var next = JSON.stringify(payload.map || {});\n      var current = payload.current || '';\n\n      // Nothing to say and nothing to correct: do not create a cart for a\n      // visitor who has not added anything.\n      if (next === '{}' && current === '') return;\n\n      if (next === posted || next === current) {\n        posted = next;\n        return;\n      }\n\n      posted = next;\n\n      var body = new FormData();\n      body.append('attributes[eta_data]', next);\n\n      var root = (window.Shopify && Shopify.routes && Shopify.routes.root) || '/';\n      fetch(root + 'cart/update.js', { method: 'POST', body: body }).catch(function () {});\n    }\n\n    window.esEtaData = { sync: sync };\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', sync);\n    } else {\n      sync();\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"cart-eta-info\"] && !Shopify.designMode) return;\n  try {\n    /* Delegated from the document rather than bound to the button: the drawer\n     re-renders its body from the server after every cart change, which replaces\n     the trigger element - a direct listener would be lost on the first update. */\n  (function () {\n    if (window.__esCartEtaInfo) return;\n    window.__esCartEtaInfo = true;\n\n    function dialog() {\n      return document.querySelector('[data-cart-eta-info-dialog]');\n    }\n\n    document.addEventListener('click', function (event) {\n      var trigger = event.target.closest('[data-cart-eta-info]');\n      if (trigger) {\n        var d = dialog();\n        if (!d) return;\n        event.preventDefault();\n        /* showModal throws if it is already open (e.g. a double click). */\n        if (!d.open) d.showModal();\n        return;\n      }\n      if (event.target.closest('[data-cart-eta-info-close]')) {\n        var open = dialog();\n        if (open && open.open) open.close();\n      }\n    });\n\n    /* Click the backdrop to dismiss: with showModal the dialog element itself\n       fills the viewport, so a click landing ON it (not on the panel) is a\n       backdrop click. */\n    document.addEventListener('click', function (event) {\n      var d = dialog();\n      if (!d || !d.open || event.target !== d) return;\n      d.close();\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"cart-promo-progress\"] && !Shopify.designMode) return;\n  try {\n    // Multibuy progress bar controller. Fetches the active promo rules from the\n  // ESR API worker (5-minute sessionStorage cache), reads the cart lines'\n  // data attributes, and renders \"Add N more\" progress for the most recently\n  // added eligible-but-unmet offer. Re-runs on cart:updated, quantity input\n  // changes, and cart drawer body re-renders (MutationObserver).\n  (function () {\n    var TTL = 5 * 60 * 1000;\n    var CACHE_KEY = 'esr:promo-rules';\n    var rulesPromise = null;\n\n    function getRules(endpoint, country) {\n      if (rulesPromise) return rulesPromise;\n      try {\n        var cached = JSON.parse(sessionStorage.getItem(CACHE_KEY));\n        if (cached && cached.endpoint === endpoint && Date.now() - cached.ts < TTL) {\n          rulesPromise = Promise.resolve(cached.rules || []);\n          return rulesPromise;\n        }\n      } catch (e) { /* ignore bad cache */ }\n      var url = endpoint.replace(/\\/+$/, '') + '/promotions';\n      if (country) url += '?country=' + encodeURIComponent(country);\n      rulesPromise = fetch(url)\n        .then(function (r) { return r.ok ? r.json() : null; })\n        .then(function (data) {\n          var rules = data && data.rules ? data.rules : [];\n          try {\n            sessionStorage.setItem(CACHE_KEY, JSON.stringify({ ts: Date.now(), endpoint: endpoint, rules: rules }));\n          } catch (e) { /* storage full/blocked - just skip caching */ }\n          return rules;\n        })\n        .catch(function () { return []; });\n      return rulesPromise;\n    }\n\n    function readLines(scope) {\n      var lines = [];\n      scope.querySelectorAll('[data-cart-line]').forEach(function (el) {\n        var qtyInput = el.querySelector('[data-quantity-input]');\n        var qty = qtyInput ? parseInt(qtyInput.value, 10) : parseInt(el.getAttribute('data-line-qty'), 10);\n        lines.push({\n          qty: qty > 0 ? qty : 0,\n          tags: (el.getAttribute('data-line-tags') || '').split('||').filter(Boolean),\n          type: el.getAttribute('data-line-type') || '',\n          onSale: el.getAttribute('data-line-on-sale') === 'true'\n        });\n      });\n      return lines;\n    }\n\n    function hasAny(list, tags) {\n      for (var i = 0; i < list.length; i++) {\n        if (tags.indexOf(list[i]) !== -1) return true;\n      }\n      return false;\n    }\n\n    // Mirrors the discount Function's qualification scope. Only tag-scoped\n    // tiers are promptable - an unscoped tier would match the whole cart.\n    function tierMatchesLine(tier, line) {\n      var included = tier.includedTags || [];\n      if (!included.length) return false;\n      if (!hasAny(included, line.tags)) return false;\n      if (hasAny(tier.excludedTags || [], line.tags)) return false;\n      var inTypes = tier.includedTypes || [];\n      if (inTypes.length && inTypes.indexOf(line.type) === -1) return false;\n      if ((tier.excludedTypes || []).indexOf(line.type) !== -1) return false;\n      if (tier.allowSaleItem === false && line.onSale) return false;\n      return true;\n    }\n\n    function formatSaving(tier) {\n      if (tier.discountType === 'percent') return tier.discountAmount + '%';\n      return '$' + tier.discountAmount;\n    }\n\n    /* Does tier 'a' pay better than tier 'b'? Types that cannot be compared\n       (a percentage against a fixed amount) are treated as an improvement -\n       better to ask than to silently drop a genuine offer. */\n    function outranks(a, b) {\n      if (!b) return true;\n      if (a.discountType !== b.discountType) return true;\n      return Number(a.discountAmount) > Number(b.discountAmount);\n    }\n\n    // Total qualifying units in the cart for this tier. Which line they came\n    // from no longer matters - the prompt asks for items, not a product.\n    function countFor(tier, lines) {\n      var count = 0;\n      lines.forEach(function (line) {\n        if (line.qty > 0 && tierMatchesLine(tier, line)) count += line.qty;\n      });\n      return count;\n    }\n\n    function compute(mount, rules) {\n      var scope = mount.closest('dialog.drawer') || mount.closest('.shopify-section') || document;\n      var lines = readLines(scope);\n      // Best = the unmet multibuy tier the cart is closest to earning.\n      var best = null;\n      rules.forEach(function (rule) {\n        if (rule.type !== 'tiered') return;\n        var tiers = (rule.tiers || []).filter(Boolean);\n        if (!tiers.length) return;\n\n        /* What the cart has ALREADY earned on this rule. Without this the bar\n           prompts towards any unmet tier, however worthless: the promos coming\n           out of the app repeat the same discount at every step (2+, 3+ and 4+\n           all at 20%), so at quantity 2 the 2+ tier was met, the bar moved to\n           the 3+ tier, and it read \"Add 1 more ... to save 20%\" to a shopper who\n           already had 20%. It also looked frozen, because the wording is the\n           same at every step (#19524265 testing).\n\n           Every tier is measured, not just the promptable ones, so a met 1+ tier\n           still counts as earned. */\n        var earned = null;\n        tiers.forEach(function (tier) {\n          var count = countFor(tier, lines);\n          if (count > 0 && count >= tier.quantity && outranks(tier, earned)) { earned = tier; }\n        });\n\n        tiers.forEach(function (tier) {\n          // Only tag-scoped multibuy tiers are promptable - an unscoped tier\n          // would match the whole cart.\n          if (!(tier.quantity >= 2)) return;\n          var count = countFor(tier, lines);\n          if (!(count > 0 && count < tier.quantity)) return;\n          // Nothing to gain, so nothing to ask for.\n          if (!outranks(tier, earned)) return;\n          /* Fewest items still needed wins, so the shopper is always shown the\n             offer within easiest reach; where two are equally close, the one\n             that pays better. */\n          var remaining = tier.quantity - count;\n          if (best === null ||\n              remaining < best.remaining ||\n              (remaining === best.remaining && outranks(tier, best.tier))) {\n            best = { tier: tier, count: count, remaining: remaining };\n          }\n        });\n      });\n      render(mount, best);\n    }\n\n    function render(mount, best) {\n      if (!best) {\n        mount.hidden = true;\n        return;\n      }\n      var textEl = mount.querySelector('[data-promo-progress-text]');\n      var barEl = mount.querySelector('[data-promo-progress-bar]');\n      if (!textEl || !barEl) return;\n      var template = mount.getAttribute('data-promo-message') || 'Add $count more $items to your cart to save $saving';\n      // Any product carrying the rule's tag counts, so the prompt asks for\n      // items rather than naming one. $product is the previous placeholder and\n      // resolves to the same word, so a message already saved in a store's\n      // settings reads correctly without being re-edited.\n      var noun = best.remaining === 1 ? 'item' : 'items';\n      textEl.textContent = template\n        .replace('$count', best.remaining)\n        .replace('$items', noun)\n        .replace('$product', noun)\n        .replace('$saving', formatSaving(best.tier))\n        .replace('$message', best.tier.discountMessage || '');\n      var pct = Math.round((best.count / best.tier.quantity) * 100);\n      barEl.style.width = Math.max(4, Math.min(100, pct)) + '%';\n      mount.hidden = false;\n    }\n\n    function runAll() {\n      var mounts = document.querySelectorAll('[data-promo-progress]');\n      if (!mounts.length) return;\n      var endpoint = mounts[0].getAttribute('data-promo-endpoint');\n      if (!endpoint) return;\n      getRules(endpoint, mounts[0].getAttribute('data-promo-country') || '').then(function (rules) {\n        document.querySelectorAll('[data-promo-progress]').forEach(function (mount) {\n          compute(mount, rules);\n        });\n      });\n    }\n\n    // Debounced with a timer, NOT requestAnimationFrame - rAF never fires in\n    // a hidden/background tab, which would freeze the bar until the next\n    // focus + event.\n    var scheduled = null;\n    function schedule() {\n      if (scheduled) return;\n      scheduled = setTimeout(function () {\n        scheduled = null;\n        runAll();\n      }, 80);\n    }\n\n    document.addEventListener('cart:updated', schedule);\n    document.addEventListener('change', function (e) {\n      if (e.target.closest('[data-quantity-input]')) schedule();\n    });\n\n    // The cart drawer re-renders its body via innerHTML after every change,\n    // replacing its mount - recompute when that happens (also keeps the cart\n    // page's bar in sync with drawer-driven changes). Mutations inside a\n    // mount are our own renders; ignore those to avoid loops.\n    var drawerEl = document.getElementById('cart-drawer');\n    if (drawerEl && window.MutationObserver) {\n      new MutationObserver(function (mutations) {\n        for (var i = 0; i < mutations.length; i++) {\n          var target = mutations[i].target;\n          if (!target.closest || !target.closest('[data-promo-progress]')) {\n            schedule();\n            return;\n          }\n        }\n      }).observe(drawerEl, { childList: true, subtree: true });\n    }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', runAll);\n    } else {\n      runAll();\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"cart-remove-confirm\"] && !Shopify.designMode) return;\n  try {\n    /* One dialog per page. The cart page and the drawer both render this snippet,\n     and on the cart page both are present at once, so the second registration is\n     dropped rather than overwriting the first. */\n  (function () {\n    if (window.esCartConfirm) return;\n\n    function dialogEl() {\n      return document.querySelector('[data-cart-remove-confirm]');\n    }\n\n    window.esCartConfirm = function () {\n      var dialog = dialogEl();\n      /* No dialog, or a browser without showModal: proceed rather than trap the\n         shopper with a remove button that does nothing. */\n      if (!dialog || typeof dialog.showModal !== 'function') return Promise.resolve(true);\n\n      return new Promise(function (resolve) {\n        var settled = false;\n        function settle(ok) {\n          if (settled) return;\n          settled = true;\n          dialog.removeEventListener('close', onClose);\n          dialog.removeEventListener('click', onClick);\n          if (dialog.open) dialog.close();\n          resolve(ok);\n        }\n        /* Escape and the backdrop both arrive as a native close, which is a\n           decline - only the confirm button resolves true. */\n        function onClose() { settle(false); }\n        function onClick(event) {\n          if (event.target.closest('[data-rc-confirm]')) { settle(true); return; }\n          if (event.target.closest('[data-rc-cancel]')) { settle(false); return; }\n          /* A click on the dialog element itself is the backdrop: the panel\n             inside it swallows clicks on the panel. */\n          if (event.target === dialog) settle(false);\n        }\n        dialog.addEventListener('close', onClose);\n        dialog.addEventListener('click', onClick);\n        dialog.showModal();\n      });\n    };\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"category-card\"] && !Shopify.designMode) return;\n  try {\n    // Belt-and-suspenders autoplay: browsers only autoplay muted, inline video,\n  // and the markup's autoplay attribute alone is unreliable. Force muted +\n  // playsinline and kick off play() (ignoring the promise rejection when a\n  // browser still blocks it). One guarded, delegated controller for all tiles.\n  (function () {\n    if (window.__esCategoryCardVideo) return;\n    window.__esCategoryCardVideo = true;\n\n    function start(video) {\n      video.muted = true;\n      video.setAttribute('muted', '');\n      video.playsInline = true;\n      video.setAttribute('playsinline', '');\n      var played = video.play();\n      if (played && typeof played.catch === 'function') played.catch(function () {});\n    }\n\n    function init(root) {\n      (root || document).querySelectorAll('.category-card__media video').forEach(start);\n    }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', function () { init(); });\n    } else {\n      init();\n    }\n\n    // Re-init when a section is re-rendered in the theme editor.\n    document.addEventListener('shopify:section:load', function (event) { init(event.target); });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"checkbox\"] && !Shopify.designMode) return;\n  try {\n    document.querySelectorAll('.checkbox__input[data-indeterminate]').forEach(function (input) {\n    input.indeterminate = true;\n  });\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"collection-card-meta\"] && !Shopify.designMode) return;\n  try {\n    // Fills in the \"From\" price on collection cards. See the doc header for why\n  // this is hydrated rather than rendered: Liquid cannot see past a\n  // collection's first 50 products, so it cannot produce a true minimum.\n  //\n  // ONE request serves the whole page - every card's handle is aliased into a\n  // single Storefront query. Nothing here runs unless the theme setting emitted\n  // the data attributes, so with the toggle off this costs zero requests.\n  (function () {\n    if (window.__ccmInit) return;\n    window.__ccmInit = true;\n\n    var SEP = ' \\u00B7 '; // middle dot per the design, written as an escape so\n    // this file stays pure ASCII - one multibyte character truncates the whole\n    // compiled snippet-scripts.js bundle.\n\n    // The braces of the shop's money format are built from char codes rather\n    // than written out: a literal Liquid-looking token inside a javascript tag\n    // is flagged by Theme Check, and Liquid is not rendered in here anyway.\n    var OPEN = String.fromCharCode(123, 123);\n    var CLOSE = String.fromCharCode(125, 125);\n\n    function money(amount, format) {\n      var cents = Math.round(amount * 100);\n      var whole = Math.floor(cents / 100);\n      var rem = cents % 100;\n      var out = String(whole).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n      // Trailing zeros are dropped, matching money_without_trailing_zeros and\n      // the design's \"From $199\". A price with real cents keeps them.\n      if (rem > 0) out = out + '.' + (rem < 10 ? '0' + rem : String(rem));\n      var start = format.indexOf(OPEN);\n      var end = format.indexOf(CLOSE);\n      if (start < 0 || end < start) return out;\n      return format.slice(0, start) + out + format.slice(end + 2);\n    }\n\n    function fill(el, amount, format, template) {\n      var span = el.querySelector('[data-ccm-price]');\n      if (!span) return;\n      var sep = document.createElement('span');\n      sep.className = 'collection-card-meta__sep';\n      sep.setAttribute('aria-hidden', 'true');\n      sep.textContent = SEP;\n      span.textContent = '';\n      span.appendChild(sep);\n      span.appendChild(document.createTextNode(template.split('__CCM_PRICE__').join(money(amount, format))));\n    }\n\n    function run() {\n      var nodes = document.querySelectorAll('[data-ccm-handle]:not([data-ccm-done])');\n      if (!nodes.length) return;\n\n      var first = nodes[0];\n      var endpoint = first.getAttribute('data-ccm-endpoint');\n      var token = first.getAttribute('data-ccm-token');\n      if (!endpoint || !token) return;\n      var format = first.getAttribute('data-ccm-money');\n      var template = first.getAttribute('data-ccm-from');\n      if (!format || !template) return;\n\n      // Mark everything up front: a card is attempted once, whether or not the\n      // request succeeds. Without this a failure would be retried on every\n      // mutation for the life of the page.\n      var byHandle = {};\n      var handles = [];\n      for (var i = 0; i < nodes.length; i++) {\n        nodes[i].setAttribute('data-ccm-done', '');\n        var h = nodes[i].getAttribute('data-ccm-handle');\n        if (!h) continue;\n        if (!byHandle[h]) { byHandle[h] = []; handles.push(h); }\n        byHandle[h].push(nodes[i]);\n      }\n      if (!handles.length) return;\n\n      var parts = [];\n      for (var j = 0; j < handles.length; j++) {\n        parts.push('c' + j + ': collection(handle: ' + JSON.stringify(handles[j]) +\n          ') { products(first: 1, sortKey: PRICE) { nodes { priceRange { minVariantPrice { amount } } } } }');\n      }\n      request('{' + parts.join(' ') + '}', 1);\n\n      function request(query, attempt) {\n        fetch(endpoint, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json', 'X-Shopify-Storefront-Access-Token': token },\n          body: JSON.stringify({ query: query })\n        }).then(function (response) {\n          if (!response.ok) throw new Error('ccm');\n          return response.json();\n        }).then(function (payload) {\n          var data = payload && payload.data;\n          if (!data) return;\n          for (var k = 0; k < handles.length; k++) {\n            var entry = data['c' + k];\n            if (!entry || !entry.products || !entry.products.nodes || !entry.products.nodes.length) continue;\n            var amount = parseFloat(entry.products.nodes[0].priceRange.minVariantPrice.amount);\n            // Floor rule: a zero minimum is a placeholder or gift card, so the\n            // segment stays empty rather than reading \"From $0\".\n            if (!(amount > 0)) continue;\n            var els = byHandle[handles[k]];\n            for (var m = 0; m < els.length; m++) fill(els[m], amount, format, template);\n          }\n        }).catch(function () {\n          // Degrade to the count alone. One retry with backoff - the storefront\n          // does return 429 under load - then stay quiet rather than storming it.\n          if (attempt < 2) {\n            setTimeout(function () { request(query, attempt + 1); }, 1500);\n          }\n        });\n      }\n    }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', run);\n    } else {\n      run();\n    }\n\n    // The collections grid appends cards on \"load more\", so pick those up too.\n    // Debounced, and each card is only ever attempted once (data-ccm-done).\n    var pending = null;\n    var observer = new MutationObserver(function () {\n      if (pending) clearTimeout(pending);\n      pending = setTimeout(run, 200);\n    });\n    if (document.body) observer.observe(document.body, { childList: true, subtree: true });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"collection-filters-drawer\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.__esCollectionFilterAccordion) return;\n    window.__esCollectionFilterAccordion = true;\n\n    var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n    function panelOf(btn) {\n      var id = btn.getAttribute('aria-controls');\n      return id ? document.getElementById(id) : null;\n    }\n\n    function expand(btn) {\n      var panel = panelOf(btn);\n      if (!panel) return;\n      btn.setAttribute('aria-expanded', 'true');\n      if (reduce) {\n        panel.style.height = 'auto';\n        return;\n      }\n      var target = panel.scrollHeight;\n      panel.style.height = '0px';\n      void panel.offsetHeight;\n      panel.style.height = target + 'px';\n      var onEnd = function (e) {\n        if (e.propertyName !== 'height') return;\n        panel.removeEventListener('transitionend', onEnd);\n        // Release to auto so the panel reflows if its content changes.\n        panel.style.height = 'auto';\n      };\n      panel.addEventListener('transitionend', onEnd);\n    }\n\n    function collapse(btn) {\n      var panel = panelOf(btn);\n      if (!panel) return;\n      btn.setAttribute('aria-expanded', 'false');\n      if (reduce) {\n        panel.style.height = '0px';\n        return;\n      }\n      // From auto -> a fixed px height, then to 0 so the transition has two\n      // concrete endpoints to animate between.\n      panel.style.height = panel.scrollHeight + 'px';\n      void panel.offsetHeight;\n      panel.style.height = '0px';\n    }\n\n    // Only one group open at a time: collapse any other expanded group.\n    function closeOthers(groups, except) {\n      var open = groups.querySelectorAll('.collection-filters__group-summary[aria-expanded=\"true\"]');\n      for (var i = 0; i < open.length; i++) {\n        if (open[i] !== except) collapse(open[i]);\n      }\n    }\n\n    document.addEventListener('click', function (e) {\n      var btn = e.target.closest ? e.target.closest('.collection-filters__group-summary') : null;\n      if (!btn) return;\n      // Scope single-open to the whole drawer so the Sort group (which sits\n      // outside .collection-filters__groups, above On Sale) is part of the set.\n      var groups = btn.closest('[data-collection-filters]');\n\n      if (btn.getAttribute('aria-expanded') === 'true') {\n        collapse(btn);\n      } else {\n        if (groups) closeOthers(groups, btn);\n        expand(btn);\n      }\n    });\n  })();\n\n  /* Dual-thumb price range: keeps the two thumbs ordered, paints the active\n     segment, and two-way-syncs with the Min/Max number fields. The actual\n     filtering is wired by the vendor; this is just the control. */\n  (function () {\n    if (window.__esCollectionPriceRange) return;\n    window.__esCollectionPriceRange = true;\n\n    function digits(value) {\n      return parseInt(String(value || '').replace(/[^0-9]/g, ''), 10);\n    }\n\n    function initRange(root) {\n      var minInput = root.querySelector('[data-range-min]');\n      var maxInput = root.querySelector('[data-range-max]');\n      var fill = root.querySelector('[data-range-fill]');\n      if (!minInput || !maxInput) return;\n\n      var price = root.parentElement;\n      var minField = price.querySelector('[data-price-min-field]');\n      var maxField = price.querySelector('[data-price-max-field]');\n      var lo = parseInt(minInput.min, 10);\n      var hi = parseInt(minInput.max, 10);\n      var span = hi - lo || 1;\n\n      function money(n) {\n        return '$' + n;\n      }\n\n      function paint() {\n        var a = parseInt(minInput.value, 10);\n        var b = parseInt(maxInput.value, 10);\n        if (fill) {\n          fill.style.setProperty('--fill-start', ((a - lo) / span) * 100 + '%');\n          fill.style.setProperty('--fill-end', ((b - lo) / span) * 100 + '%');\n        }\n      }\n\n      function onMin() {\n        if (parseInt(minInput.value, 10) > parseInt(maxInput.value, 10)) {\n          minInput.value = maxInput.value;\n        }\n        if (minField) minField.value = money(minInput.value);\n        paint();\n      }\n\n      function onMax() {\n        if (parseInt(maxInput.value, 10) < parseInt(minInput.value, 10)) {\n          maxInput.value = minInput.value;\n        }\n        if (maxField) maxField.value = money(maxInput.value);\n        paint();\n      }\n\n      minInput.addEventListener('input', onMin);\n      maxInput.addEventListener('input', onMax);\n\n      // Typing in a field moves the matching thumb (clamped to the other one).\n      if (minField) {\n        minField.addEventListener('change', function () {\n          var v = digits(minField.value);\n          if (isNaN(v)) v = lo;\n          v = Math.max(lo, Math.min(v, parseInt(maxInput.value, 10)));\n          minInput.value = v;\n          minField.value = money(v);\n          paint();\n        });\n      }\n      if (maxField) {\n        maxField.addEventListener('change', function () {\n          var v = digits(maxField.value);\n          if (isNaN(v)) v = hi;\n          v = Math.min(hi, Math.max(v, parseInt(minInput.value, 10)));\n          maxInput.value = v;\n          maxField.value = money(v);\n          paint();\n        });\n      }\n\n      paint();\n    }\n\n    function initAll() {\n      var roots = document.querySelectorAll('[data-price-range]');\n      for (var i = 0; i < roots.length; i++) {\n        /* Guard per root so a re-init (injected controls) does not bind twice. */\n        if (roots[i].__esRangeInit) continue;\n        roots[i].__esRangeInit = true;\n        initRange(roots[i]);\n      }\n    }\n\n    /* Exposed so client-rendered price controls (Constructor facets) can be wired\n       after injection - this module otherwise only runs once on load. */\n    window.esCollectionPriceRange = { init: initAll };\n\n    if (document.readyState !== 'loading') initAll();\n    else document.addEventListener('DOMContentLoaded', initAll);\n  })();\n\n  /* Mobile sort: the radios re-sort via Shopify's native ?sort_by (set on the\n     current URL so other params are preserved). Sort needs no vendor wiring. */\n  (function () {\n    if (window.__esCollectionSortRadios) return;\n    window.__esCollectionSortRadios = true;\n\n    document.addEventListener('change', function (e) {\n      var input = e.target;\n      if (!input || input.name !== 'sort_by') return;\n      if (!input.closest('[data-sort-options]')) return;\n      var url = new URL(window.location.href);\n      url.searchParams.set('sort_by', input.value);\n      window.location.href = url.toString();\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"collection-sort\"] && !Shopify.designMode) return;\n  try {\n    /* Constructor-driven sort for the collection sort control.\n\n     The control is rendered by the collection-header section while the grid it sorts\n     lives in the collection section, and sections cannot call into each other - so the\n     two talk through events on document: \"constructor:sort-options\" in (the shared\n     facet module announcing what Constructor offers and what is selected), and\n     \"constructor:sort\" out. The grid owns the query; this is only a view of it.\n\n     Until that first event arrives the control is left exactly as Liquid rendered it,\n     which is what keeps the Shopify ?sort_by behaviour intact when Constructor is off. */\n  (function () {\n    if (window.__esCollectionSortCnstrc) return;\n    window.__esCollectionSortCnstrc = true;\n\n    function label(root, name) {\n      var el = root.querySelector('[data-sort-label]');\n      if (!el) return;\n      var prefix = root.getAttribute('data-sort-prefix') || 'Sort by';\n      el.textContent = name ? prefix + ': ' + name : prefix;\n    }\n\n    /* Each option is a real link to this page with the sort param set, matching what\n       the URL becomes when it is chosen. Anchors, not buttons: the option styling is\n       written for anchors, so a button arrives with native chrome the class never\n       resets - and a real href means the control still works if the click handler\n       never binds. The click is intercepted so the grid re-queries in place. */\n    function href(paramName, paramValue) {\n      var url = new URL(window.location.href);\n      url.searchParams.set(paramName, paramValue);\n      /* A new sort is a new result set, so the loaded depth no longer applies. */\n      url.searchParams.delete('loaded');\n      /* The two engines name the parameter differently - Constructor sorts on\n         \"sort\", Shopify on \"sort_by\" - so a URL that arrived carrying the other\n         one would keep a stale sort in the address after the engine switched.\n         Only the one being set survives (#19669138). */\n      if (paramName !== 'sort_by') url.searchParams.delete('sort_by');\n      if (paramName !== 'sort') url.searchParams.delete('sort');\n      return url.pathname + url.search;\n    }\n\n    function build(root, detail) {\n      var list = root.querySelector('.collection-sort__options');\n      if (!list) return;\n      list.textContent = '';\n      var selectedName = '';\n      var paramName = detail.param || 'sort';\n\n      detail.options.forEach(function (o) {\n        if (o.active) selectedName = o.label;\n\n        var li = document.createElement('li');\n        var link = document.createElement('a');\n        link.className = 'collection-sort__option' + (o.active ? ' collection-sort__option--active' : '');\n        link.href = href(paramName, o.param);\n        link.setAttribute('data-cnstrc-sort-choice', o.value);\n        if (o.active) link.setAttribute('aria-current', 'true');\n        link.textContent = o.label;\n        li.appendChild(link);\n        list.appendChild(li);\n      });\n\n      label(root, selectedName);\n      root.setAttribute('data-cnstrc-sort-driven', 'true');\n    }\n\n    document.addEventListener('constructor:sort-options', function (e) {\n      var detail = e.detail || {};\n      if (!detail.options || !detail.options.length) return;\n      document.querySelectorAll('[data-collection-sort]').forEach(function (root) {\n        build(root, detail);\n      });\n    });\n\n    document.addEventListener('click', function (e) {\n      var choice = e.target.closest ? e.target.closest('[data-cnstrc-sort-choice]') : null;\n      if (!choice) return;\n      e.preventDefault();\n      var root = choice.closest('[data-collection-sort]');\n      /* Close the disclosure so the shopper sees the grid update, not the open list. */\n      if (root) root.open = false;\n      document.dispatchEvent(\n        new CustomEvent('constructor:sort', { detail: { value: choice.getAttribute('data-cnstrc-sort-choice') } })\n      );\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"constructor-facets\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.esrFacets) return;\n\n    /* Facet values travel as repeated params (f.size=Round&f.size=Square) rather\n       than one delimited value, so a value containing the delimiter cannot corrupt\n       the rest. The price range is a single \"min-max\" value under the same prefix. */\n    var PREFIX = 'f.';\n    var SORT_PARAM = 'sort';\n\n    /* Internally a sort is \"sortBy|sortOrder\", because Constructor needs both. In the\n       URL it is written Shopify's way - price-descending - which is prettier than an\n       encoded pipe and matches what shoppers already see on this site. Decoding splits\n       on the LAST dash so a sort_by containing one still round-trips. */\n    function encodeSort(value) {\n      return value ? value.replace('|', '-') : '';\n    }\n\n    function decodeSort(param) {\n      if (!param) return null;\n      var i = param.lastIndexOf('-');\n      if (i < 1) return null;\n      return param.slice(0, i) + '|' + param.slice(i + 1);\n    }\n\n    window.esrFacets = {\n      create: function (config) {\n        var options = config || {};\n        var onChange = options.onChange || function () {};\n        var syncUrl = options.syncUrl === true;\n        /* Search shows sort inside the drawer at every breakpoint. A collection page\n           only does so on mobile, because its desktop sort lives in the collection\n           header - so the group takes the existing mobile-only modifier there. */\n        var sortGroupClass = options.sortDesktop === true\n          ? 'collection-filters__group--sort-search'\n          : 'collection-filters__group--sort';\n\n        /* Facets the surface has asked to leave out of the drawer, from a\n           merchant-entered comma-separated list of labels (\"Pattern, Product\n           Type, Colour/Finish\"). Compared loosely - lower-cased with everything\n           but letters and digits stripped - so \"Product Type\" hides the facet\n           whether Constructor names it product_type or Product Type, and a\n           trailing space or a slash in the setting cannot miss. Values already\n           selected for a hidden facet (from a shared URL) still apply and still\n           show as chips, so the shopper can clear them. */\n        function facetKey(value) {\n          return String(value == null ? '' : value).toLowerCase().replace(/[^a-z0-9]+/g, '');\n        }\n        var hiddenFacets = [];\n        (Array.isArray(options.hiddenFacets)\n          ? options.hiddenFacets\n          : String(options.hiddenFacets || '').split(',')\n        ).forEach(function (label) {\n          var key = facetKey(label);\n          if (key) hiddenFacets.push(key);\n        });\n        function isHiddenFacet(f) {\n          if (!hiddenFacets.length || !f) return false;\n          return hiddenFacets.indexOf(facetKey(f.name)) !== -1\n            || hiddenFacets.indexOf(facetKey(f.display_name)) !== -1;\n        }\n\n        /* Selected values, keyed by facet name: multi-select facets hold an array of\n           values, the price range holds a single \"min-max\" string. Constructor takes\n           exactly that shape as its filters argument. */\n        var selected = {};\n        /* Constructor identifies a sort option by sort_by AND sort_order together\n           (price appears twice, ascending and descending), so both are held and the\n           radio value encodes the pair. Null means the engine's own default. */\n        var sort = null;\n\n        var facetsHost = document.querySelector('[data-cnstrc-facets]');\n        var sortHost = document.querySelector('[data-cnstrc-sort]');\n        var chipsHost = document.querySelector('[data-cnstrc-chips]');\n        /* Translated label comes through a data attribute: Liquid is not rendered\n           inside a javascript tag. */\n        var SORT_LABEL = (sortHost && sortHost.getAttribute('data-sort-label')) || 'Sort by';\n\n        function hasFilters() {\n          return Object.keys(selected).some(function (k) {\n            return selected[k] && selected[k].length;\n          });\n        }\n\n        /* ---------- URL ---------- */\n\n        function readUrl() {\n          var params = new URL(window.location.href).searchParams;\n          params.forEach(function (value, key) {\n            if (key.indexOf(PREFIX) !== 0) return;\n            var name = key.slice(PREFIX.length);\n            if (!name) return;\n            selected[name] = (selected[name] || []).concat([value]);\n          });\n          sort = decodeSort(params.get(SORT_PARAM));\n        }\n\n        function writeUrl() {\n          if (!syncUrl) return;\n          var url = new URL(window.location.href);\n          /* Rebuild the facet params wholesale: deleting per key would leave stale\n             values behind for a facet that has just been emptied. */\n          /* Array.from, not slice.call: a URLSearchParams iterator has no length, so\n             slice.call returns an empty array and the stale params survive - which left\n             a cleared filter in the URL and duplicated values on repeated toggles. */\n          Array.from(url.searchParams.keys()).forEach(function (key) {\n            if (key.indexOf(PREFIX) === 0) url.searchParams.delete(key);\n          });\n          Object.keys(selected).forEach(function (name) {\n            (selected[name] || []).forEach(function (value) {\n              url.searchParams.append(PREFIX + name, value);\n            });\n          });\n          if (sort) url.searchParams.set(SORT_PARAM, encodeSort(sort));\n          else url.searchParams.delete(SORT_PARAM);\n          window.history.replaceState(window.history.state, '', url.toString());\n        }\n\n        /* ---------- Rendering ---------- */\n\n        /* Clones the Liquid-rendered template so injected controls carry the real\n           design-system markup: the checkbox's hidden input plus its styled box, and\n           the inline plus/minus icons. Building these as strings produced unstyled\n           markup. */\n        function tpl(name) {\n          var t = document.querySelector('[data-cnstrc-tpl=\"' + name + '\"]');\n          return t ? t.content.firstElementChild.cloneNode(true) : null;\n        }\n\n        /* ---------- Colour swatches ----------\n           Constructor's colour facet arrives as plain values (\"Natural Timber\"),\n           and the swatches live in the colour_swatch metaobjects, published by\n           the filter drawer as handle -> { c: hex, i: image url }.\n\n           Matched on HANDLE, not label: product-level swatches are named after\n           the colour they are, so several share a label (staging has six\n           labelled \"Green\") and a label lookup cannot choose between them. The\n           family entry is always the plain handleized name, product ones are\n           prefixed. */\n        function swatchHandle(value) {\n          return String(value == null ? '' : value)\n            .toLowerCase()\n            .replace(/&/g, ' ')\n            .replace(/[^a-z0-9]+/g, '-')\n            .replace(/^-+|-+$/g, '');\n        }\n\n        /* Mirrors the Liquid checkbox's rule: a hex brighter than 220 gets a grey\n           ring so white and cream don't vanish against the drawer. Image swatches\n           are always ringed - the artwork can be pale at its edges and we cannot\n           measure it here. */\n        function isLightSwatch(hex) {\n          var h = String(hex || '').replace('#', '');\n          if (h.length === 3) { h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2]; }\n          if (h.length !== 6) { return false; }\n          var r = parseInt(h.slice(0, 2), 16);\n          var g = parseInt(h.slice(2, 4), 16);\n          var b = parseInt(h.slice(4, 6), 16);\n          if (isNaN(r) || isNaN(g) || isNaN(b)) { return false; }\n          /* Shopify's color_brightness weighting, so JS and Liquid agree. */\n          return ((r * 299 + g * 587 + b * 114) / 1000) > 220;\n        }\n\n        /* Turns a cloned option into a swatch checkbox. Returns false when there\n           is nothing to show - no entry, or an entry with neither colour nor\n           image - and the caller leaves the standard checkbox alone. */\n        function applySwatch(option, value) {\n          var map = window.esrColourSwatches;\n          if (!map) { return false; }\n          var sw = map[swatchHandle(value)];\n          if (!sw || (!sw.c && !sw.i && !sw.g)) { return false; }\n          option.classList.add('checkbox--colour');\n          if (sw.c) { option.style.setProperty('--checkbox-colour', sw.c); }\n          /* Gradient and image share --checkbox-swatch-image, which the\n             stylesheet reads as background-image - a linear-gradient() is a\n             background-image, so no second variable is needed. The image is set\n             LAST on purpose: with both present the later set wins, which is the\n             image > gradient > colour order the old theme documented. */\n          if (sw.g) { option.style.setProperty('--checkbox-swatch-image', sw.g); }\n          if (sw.i) { option.style.setProperty('--checkbox-swatch-image', 'url(\"' + sw.i + '\")'); }\n          /* A gradient is ringed like an image: it cannot be measured from one\n             hex, and the two the client asked for both end in white, which would\n             otherwise vanish into the drawer. */\n          if (sw.i || sw.g || isLightSwatch(sw.c)) { option.classList.add('checkbox--colour-light'); }\n          return true;\n        }\n\n        /* The footer's \"View N results\" was rendered by Liquid with the collection's\n           full total (or no number at all on search) and never touched again, so it\n           read 189 while the grid header said 28. The button carries the translated\n           label as a template; fill in Constructor's total on every render, the way\n           the grid header does. Only the label span is written, so the button's own\n           markup and listeners are left alone. */\n        function renderCount(total) {\n          if (typeof total !== 'number') return;\n          document.querySelectorAll('[data-cnstrc-view-results]').forEach(function (button) {\n            var tpl = button.getAttribute('data-view-results-tpl');\n            if (!tpl) return;\n            var label = button.querySelector('.button__label') || button;\n            label.textContent = tpl.replace('XCOUNTX', total);\n          });\n        }\n\n        /* Which facet is the colour one. Matched on the name rather than hard\n           coded, so a rename in Constructor does not silently drop the swatches;\n           covers colour and color. */\n        function isColourFacet(f) {\n          return /colou?r/i.test((f && (f.display_name || f.name)) || '');\n        }\n\n        /* Groups the shopper has opened, so a re-render after filtering does not\n           collapse the drawer under them. */\n        function openFacets() {\n          if (!facetsHost) return {};\n          var open = {};\n          facetsHost.querySelectorAll('[data-facet-group]').forEach(function (group) {\n            var summary = group.querySelector('.collection-filters__group-summary');\n            if (summary && summary.getAttribute('aria-expanded') === 'true') {\n              open[group.getAttribute('data-facet-group')] = true;\n            }\n          });\n          return open;\n        }\n\n        function renderSort(sortOptions) {\n          if (!sortHost) return;\n          var usable = (sortOptions || []).filter(function (o) { return !o.hidden; });\n          if (!usable.length) {\n            sortHost.textContent = '';\n            return;\n          }\n\n          var wasOpen = !!sortHost.querySelector('[aria-expanded=\"true\"]');\n          var group = tpl('group');\n          if (!group) return;\n          var id = 'cf-cnstrc-sort';\n\n          group.classList.add(sortGroupClass);\n          group.querySelector('[data-tpl-label]').textContent = SORT_LABEL;\n          var summary = group.querySelector('.collection-filters__group-summary');\n          var panel = group.querySelector('.collection-filters__group-panel');\n          summary.setAttribute('aria-controls', id);\n          summary.setAttribute('aria-expanded', wasOpen ? 'true' : 'false');\n          panel.id = id;\n          panel.style.height = wasOpen ? 'auto' : '0';\n\n          var body = group.querySelector('[data-tpl-body]');\n          body.classList.add('collection-filters__group-body--sort');\n\n          usable.forEach(function (o) {\n            var option = tpl('sort-option');\n            if (!option) return;\n            var value = o.sort_by + '|' + o.sort_order;\n            var oid = id + '-' + value.replace(/[^a-z0-9]+/gi, '-');\n            var input = option.querySelector('.radio__input');\n            option.setAttribute('for', oid);\n            input.id = oid;\n            input.value = value;\n            /* Before a shopper chooses, the engine's own selected option is checked. */\n            input.checked = sort ? sort === value : o.status === 'selected';\n            input.setAttribute('data-cnstrc-sort-value', value);\n            option.querySelector('.radio__label').textContent = o.display_name;\n            body.appendChild(option);\n          });\n\n          sortHost.textContent = '';\n          sortHost.appendChild(group);\n\n          /* Anything outside the drawer that presents the same options - the desktop\n             sort control on a collection page lives in a different section - rebuilds\n             from this event rather than duplicating the render. */\n          var chosen = currentSort(usable);\n          document.dispatchEvent(\n            new CustomEvent('constructor:sort-options', {\n              detail: {\n                selected: chosen,\n                param: SORT_PARAM,\n                options: usable.map(function (o) {\n                  var value = o.sort_by + '|' + o.sort_order;\n                  return {\n                    value: value,\n                    param: encodeSort(value),\n                    label: o.display_name,\n                    active: value === chosen\n                  };\n                })\n              }\n            })\n          );\n        }\n\n        /* The engine's default counts as the selection until the shopper picks one. */\n        function currentSort(usable) {\n          if (sort) return sort;\n          var chosen = (usable || []).filter(function (o) { return o.status === 'selected'; })[0];\n          return chosen ? chosen.sort_by + '|' + chosen.sort_order : null;\n        }\n\n        function renderFacets(facets) {\n          if (!facetsHost) return;\n          var open = openFacets();\n          facetsHost.textContent = '';\n\n          (facets || []).forEach(function (f) {\n            /* compare_at_price comes back as a list of individual prices rather than\n               an is-discounted flag, so it cannot drive the designed On Sale toggle\n               and is left out until Constructor exposes a boolean facet. */\n            if (f.hidden || f.name === 'compare_at_price' || isHiddenFacet(f)) return;\n\n            var group = tpl('group');\n            if (!group) return;\n            var id = 'cf-cnstrc-' + f.name;\n            var isOpen = !!open[f.name];\n\n            group.setAttribute('data-facet-group', f.name);\n            group.querySelector('[data-tpl-label]').textContent = f.display_name || f.name;\n\n            var summary = group.querySelector('.collection-filters__group-summary');\n            var panel = group.querySelector('.collection-filters__group-panel');\n            summary.setAttribute('aria-controls', id);\n            summary.setAttribute('aria-expanded', isOpen ? 'true' : 'false');\n            panel.id = id;\n            /* The panel is height: 0 by default and the accordion drives it inline, so\n               a re-render has to restore BOTH halves of the state. Leaving the height\n               unset on a group marked expanded collapsed its contents while the icon\n               showed minus, which took two clicks to recover. auto is what the\n               accordion itself settles on once its transition ends. */\n            panel.style.height = isOpen ? 'auto' : '0';\n\n            var body = group.querySelector('[data-tpl-body]');\n\n            if (f.type === 'range') {\n              var price = tpl('price');\n              if (price) {\n                /* Constructor gives the facet's own bounds; the current selection (if\n                   any) sets the thumb positions, otherwise they sit at the extremes. */\n                var floor = Math.floor(Number(f.min));\n                var ceiling = Math.ceil(Number(f.max));\n                var chosenRange = ((selected[f.name] || [])[0] || '').split('-');\n                var lo = chosenRange[0] !== undefined && chosenRange[0] !== '' ? chosenRange[0] : floor;\n                var hi = chosenRange[1] !== undefined && chosenRange[1] !== '' ? chosenRange[1] : ceiling;\n\n                price.setAttribute('data-facet-range', f.name);\n                [['[data-range-min]', lo], ['[data-range-max]', hi]].forEach(function (pair) {\n                  var el = price.querySelector(pair[0]);\n                  if (!el) return;\n                  el.min = floor;\n                  el.max = ceiling;\n                  el.value = pair[1];\n                });\n                var minField = price.querySelector('[data-price-min-field]');\n                var maxField = price.querySelector('[data-price-max-field]');\n                if (minField) minField.value = '$' + lo;\n                if (maxField) maxField.value = '$' + hi;\n\n                body.appendChild(price);\n              }\n            } else {\n              var chosen = selected[f.name] || [];\n              (f.options || []).forEach(function (o) {\n                var option = tpl('option');\n                if (!option) return;\n                var oid = id + '-' + String(o.value).replace(/[^a-z0-9]+/gi, '-');\n                var input = option.querySelector('.checkbox__input');\n                option.setAttribute('for', oid);\n                input.id = oid;\n                input.value = o.value;\n                input.checked = chosen.indexOf(o.value) !== -1;\n                input.setAttribute('data-facet-name', f.name);\n                input.setAttribute('data-facet-value', o.value);\n                option.querySelector('.checkbox__label').textContent = o.display_name || o.value;\n                /* Colour facets render as swatches where one exists; every other\n                   facet, and any colour with no swatch, keeps the plain checkbox. */\n                if (isColourFacet(f)) { applySwatch(option, o.value); }\n                var count = option.querySelector('.checkbox__count');\n                if (count) {\n                  if (o.count == null) count.remove();\n                  else count.textContent = '(' + o.count + ')';\n                }\n                body.appendChild(option);\n              });\n            }\n\n            facetsHost.appendChild(group);\n          });\n\n          /* Wire the price slider only once the groups are in the document: the\n             theme's range module queries the document, so calling it while a group is\n             still detached finds nothing. It binds on load only and guards per root,\n             so this is both necessary for injected controls and safe to call on every\n             render. */\n          if (window.esCollectionPriceRange) window.esCollectionPriceRange.init();\n\n          renderChips(facets);\n        }\n\n        /* Applied-filter chips, with Clear all as the final item so it sits inline\n           with the last row rather than dropping to its own line. */\n        function renderChips(facets) {\n          if (!chipsHost) return;\n          var list = chipsHost.querySelector('.collection-filters__chips');\n          if (!list) return;\n\n          var labels = {};\n          (facets || []).forEach(function (f) { labels[f.name] = f.display_name || f.name; });\n\n          list.textContent = '';\n          var any = false;\n          Object.keys(selected).forEach(function (name) {\n            (selected[name] || []).forEach(function (value) {\n              var chip = tpl('chip');\n              if (!chip) return;\n              any = true;\n              var btn = chip.querySelector('[data-facet-remove]');\n              btn.setAttribute('data-facet-name', name);\n              btn.setAttribute('data-facet-value', value);\n              chip.querySelector('[data-tpl-label]').textContent = (labels[name] || name) + ': ' + value;\n              list.appendChild(chip);\n            });\n          });\n\n          if (any) {\n            var clear = tpl('clear');\n            if (clear) list.appendChild(clear);\n          }\n          chipsHost.hidden = !any;\n\n          /* The footer's Clear tracks the chips: nothing applied, nothing to clear,\n             and View results then spans the footer on its own. Scoped to the footer so\n             it does not catch the Clear all inside the chip list. */\n          var footerClear = document.querySelector('.collection-filters__footer [data-cnstrc-clear]');\n          if (footerClear) footerClear.hidden = !any;\n        }\n\n        function toggleValue(name, value, on) {\n          var current = selected[name] || [];\n          var i = current.indexOf(value);\n          if (on && i === -1) current.push(value);\n          if (!on && i !== -1) current.splice(i, 1);\n          if (current.length) selected[name] = current;\n          else delete selected[name];\n        }\n\n        function changed() {\n          writeUrl();\n          onChange();\n        }\n\n        /* ---------- Events ----------\n           Delegated, so controls rebuilt on every render keep working. */\n\n        document.addEventListener('change', function (e) {\n          if (!e.target.closest) return;\n\n          var box = e.target.closest('[data-facet-name][type=\"checkbox\"]');\n          if (box) {\n            toggleValue(box.getAttribute('data-facet-name'), box.getAttribute('data-facet-value'), box.checked);\n            changed();\n            return;\n          }\n\n          var sortRadio = e.target.closest('[data-cnstrc-sort-value]');\n          if (sortRadio) {\n            sort = sortRadio.value;\n            changed();\n            return;\n          }\n\n          /* Price: the slider and the Min/Max fields two-way sync inside the theme's\n             range module, so either can be the trigger. Range inputs fire change on\n             release, which is the right moment to re-query rather than every drag\n             frame. */\n          var priceRoot = e.target.closest('[data-facet-range]');\n          if (priceRoot) {\n            var name = priceRoot.getAttribute('data-facet-range');\n            var slider = priceRoot.querySelector('[data-range-min]');\n            var sliderMax = priceRoot.querySelector('[data-range-max]');\n            if (!slider || !sliderMax) return;\n\n            var digits = function (v) { return parseInt(String(v || '').replace(/[^0-9]/g, ''), 10); };\n            var lo = digits(slider.value);\n            var hi = digits(sliderMax.value);\n            var floor = digits(slider.min);\n            var ceiling = digits(slider.max);\n\n            /* Both thumbs at the extremes means no price filter, so drop it rather\n               than sending a range that matches everything. */\n            if (lo <= floor && hi >= ceiling) delete selected[name];\n            else selected[name] = [lo + '-' + hi];\n            changed();\n          }\n        });\n\n        document.addEventListener('click', function (e) {\n          if (!e.target.closest) return;\n\n          var chip = e.target.closest('[data-facet-remove]');\n          if (chip) {\n            toggleValue(chip.getAttribute('data-facet-name'), chip.getAttribute('data-facet-value'), false);\n            changed();\n            return;\n          }\n          if (e.target.closest('[data-cnstrc-clear]')) {\n            selected = {};\n            changed();\n          }\n        });\n\n        /* A sort control outside the drawer reports its choice here rather than\n           reaching into this module's state. */\n        document.addEventListener('constructor:sort', function (e) {\n          var value = e.detail && e.detail.value;\n          if (value && value.indexOf('|') === -1) value = decodeSort(value);\n          if (!value || value === sort) return;\n          sort = value;\n          changed();\n        });\n\n        if (syncUrl) readUrl();\n\n        return {\n          hasFilters: hasFilters,\n\n          /* Adds the current filters and sort to a request params object. */\n          applyTo: function (params) {\n            var out = params || {};\n            if (hasFilters()) out.filters = selected;\n            if (sort) {\n              var pair = sort.split('|');\n              out.sortBy = pair[0];\n              out.sortOrder = pair[1];\n            }\n            return out;\n          },\n\n          /* Rebuilds the drawer from a Constructor response. Skip while appending a\n             further page: the facets and sort options are unchanged by paging, and\n             rebuilding would drop the shopper's open group and scroll position\n             mid-interaction. */\n          render: function (response) {\n            renderSort(response && response.sort_options);\n            renderFacets(response && response.facets);\n            renderCount(response && response.total_num_results);\n          }\n        };\n      }\n    };\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"date-picker\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n\n    function root(el) { return el.closest('[data-date-picker]'); }\n    function pad(n) { return (n < 10 ? '0' : '') + n; }\n    function toISO(y, m, d) { return y + '-' + pad(m + 1) + '-' + pad(d); }\n    function fromISO(s) {\n      if (!s) return null;\n      var p = s.split('-');\n      if (p.length !== 3) return null;\n      return { y: parseInt(p[0], 10), m: parseInt(p[1], 10) - 1, d: parseInt(p[2], 10) };\n    }\n    function fmt(y, m, d) { return pad(d) + ' / ' + pad(m + 1) + ' / ' + y; }\n    function nowParts() { var d = new Date(); return { y: d.getFullYear(), m: d.getMonth(), d: d.getDate() }; }\n\n    function state(node) {\n      if (!node._dp) node._dp = { view: null };\n      return node._dp;\n    }\n    function selectedISO(node) {\n      return node.querySelector('[data-date-input]').value || null;\n    }\n\n    function buildSelectors(node) {\n      var st = state(node);\n      var monthSel = node.querySelector('[data-date-month]');\n      var yearSel = node.querySelector('[data-date-year]');\n      if (monthSel.options.length === 0) {\n        for (var i = 0; i < 12; i++) {\n          var o = document.createElement('option');\n          o.value = i;\n          o.textContent = MONTHS[i];\n          monthSel.appendChild(o);\n        }\n      }\n      if (yearSel.options.length === 0) {\n        var thisYear = new Date().getFullYear();\n        for (var y = thisYear - 100; y <= thisYear + 10; y++) {\n          var oy = document.createElement('option');\n          oy.value = y;\n          oy.textContent = y;\n          yearSel.appendChild(oy);\n        }\n      }\n      monthSel.value = st.view.m;\n      yearSel.value = st.view.y;\n    }\n\n    function bounds(node) {\n      return { min: node.getAttribute('data-min') || null, max: node.getAttribute('data-max') || null };\n    }\n\n    function render(node) {\n      var st = state(node);\n      var days = node.querySelector('[data-date-days]');\n      node.querySelector('[data-date-month]').value = st.view.m;\n      node.querySelector('[data-date-year]').value = st.view.y;\n      node.querySelector('[data-date-month-text]').textContent = MONTHS[st.view.m];\n      node.querySelector('[data-date-year-text]').textContent = st.view.y;\n      days.innerHTML = '';\n      var y = st.view.y, m = st.view.m;\n      var startDow = new Date(y, m, 1).getDay();\n      var daysInMonth = new Date(y, m + 1, 0).getDate();\n      var prevDays = new Date(y, m, 0).getDate();\n      var b = bounds(node);\n      var selected = selectedISO(node);\n      for (var i = 0; i < 42; i++) {\n        var btn = document.createElement('button');\n        btn.type = 'button';\n        btn.className = 'date-picker__day';\n        var dayNum, cy = y, cm = m, other = false;\n        if (i < startDow) { dayNum = prevDays - startDow + 1 + i; cm = m - 1; other = true; if (cm < 0) { cm = 11; cy = y - 1; } }\n        else if (i >= startDow + daysInMonth) { dayNum = i - (startDow + daysInMonth) + 1; cm = m + 1; other = true; if (cm > 11) { cm = 0; cy = y + 1; } }\n        else { dayNum = i - startDow + 1; }\n        var iso = toISO(cy, cm, dayNum);\n        btn.textContent = dayNum;\n        btn.setAttribute('data-iso', iso);\n        if (other) { btn.className += ' date-picker__day--other'; btn.disabled = true; }\n        if (b.min && iso < b.min) btn.disabled = true;\n        if (b.max && iso > b.max) btn.disabled = true;\n        if (selected && iso === selected && !other) {\n          btn.className += ' date-picker__day--selected';\n          btn.setAttribute('aria-current', 'date');\n        }\n        days.appendChild(btn);\n      }\n    }\n\n    function open(node) {\n      var trig = node.querySelector('[data-date-picker-trigger]');\n      var st = state(node);\n      var base = fromISO(selectedISO(node)) || nowParts();\n      st.view = { y: base.y, m: base.m };\n      trig.setAttribute('aria-expanded', 'true');\n      node.querySelector('[data-date-picker-menu]').hidden = false;\n      node.classList.add('date-picker--open');\n      buildSelectors(node);\n      render(node);\n    }\n\n    function close(node) {\n      node.querySelector('[data-date-picker-trigger]').setAttribute('aria-expanded', 'false');\n      node.querySelector('[data-date-picker-menu]').hidden = true;\n      node.classList.remove('date-picker--open');\n    }\n\n    /* Commit the chosen day immediately (no Done press needed). Keeps the\n       popover open so the user can pick another date; Done/Close dismiss it. */\n    function selectDay(node, iso) {\n      var input = node.querySelector('[data-date-input]');\n      var valueEl = node.querySelector('[data-date-picker-value]');\n      var p = fromISO(iso);\n      input.value = iso;\n      valueEl.textContent = fmt(p.y, p.m, p.d);\n      input.dispatchEvent(new Event('change', { bubbles: true }));\n      render(node);\n    }\n\n    document.addEventListener('click', function (e) {\n      var trig = e.target.closest('[data-date-picker-trigger]');\n      if (trig) {\n        var n = root(trig);\n        if (trig.getAttribute('aria-expanded') === 'true') { close(n); } else { open(n); }\n        return;\n      }\n      var prev = e.target.closest('[data-date-prev]');\n      if (prev) { var np = root(prev); var sp = state(np); sp.view.m--; if (sp.view.m < 0) { sp.view.m = 11; sp.view.y--; } render(np); return; }\n      var next = e.target.closest('[data-date-next]');\n      if (next) { var nn = root(next); var sn = state(nn); sn.view.m++; if (sn.view.m > 11) { sn.view.m = 0; sn.view.y++; } render(nn); return; }\n      var day = e.target.closest('.date-picker__day');\n      if (day && !day.disabled) { selectDay(root(day), day.getAttribute('data-iso')); return; }\n      if (e.target.closest('[data-date-done]')) { close(root(e.target)); return; }\n      if (e.target.closest('[data-date-close]')) { close(root(e.target)); return; }\n      Array.prototype.forEach.call(document.querySelectorAll('[data-date-picker].date-picker--open'), function (node) {\n        if (!node.contains(e.target)) close(node);\n      });\n    });\n\n    document.addEventListener('change', function (e) {\n      if (e.target.matches('[data-date-month]')) { var n = root(e.target); state(n).view.m = parseInt(e.target.value, 10); render(n); }\n      else if (e.target.matches('[data-date-year]')) { var n2 = root(e.target); state(n2).view.y = parseInt(e.target.value, 10); render(n2); }\n    });\n\n    document.addEventListener('keydown', function (e) {\n      if (e.key === 'Escape') {\n        Array.prototype.forEach.call(document.querySelectorAll('[data-date-picker].date-picker--open'), close);\n        return;\n      }\n      var day = e.target.closest ? e.target.closest('.date-picker__day') : null;\n      if (!day) return;\n      var move = 0;\n      if (e.key === 'ArrowRight') move = 1;\n      else if (e.key === 'ArrowLeft') move = -1;\n      else if (e.key === 'ArrowDown') move = 7;\n      else if (e.key === 'ArrowUp') move = -7;\n      if (move !== 0) {\n        e.preventDefault();\n        var btns = Array.prototype.slice.call(root(day).querySelectorAll('.date-picker__day'));\n        var target = btns[btns.indexOf(day) + move];\n        if (target) target.focus();\n      }\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"drawer\"] && !Shopify.designMode) return;\n  try {\n    // Global controller for all `drawer` shells (defined once). Opens any\n  // <dialog class=\"drawer\"> from a [data-drawer-trigger=\"<id>\"] element, and\n  // closes on the X, an overlay/outside click, or Escape (native). Body scroll\n  // is locked while open; focus returns to the trigger on close.\n  //\n  // Drawers can also be opened/closed from code via window.esDrawer.open(id)\n  // and window.esDrawer.close(id) - e.g. the cart drawer pops open after an\n  // add-to-cart - so the scroll-lock and return-focus handling stays in one\n  // place rather than each feature calling showModal() itself.\n  (function () {\n    if (window.__esDrawerInit) return;\n    window.__esDrawerInit = true;\n\n    var lastTrigger = null;\n\n    function lockScroll() {\n      document.documentElement.style.overflow = 'hidden';\n    }\n\n    function unlockScroll() {\n      // Something underneath may still be holding the page: another drawer, or\n      // the predictive search panel this drawer was opened from (it locks the\n      // page on mobile and marks itself with data-scroll-locked). Releasing the\n      // lock then would let the page scroll behind an overlay that is still\n      // open - the closing drawer does not own the lock outright (#19502854).\n      // The drawer that is closing has already dropped its own [open].\n      if (document.querySelector('dialog.drawer[open], [data-scroll-locked]')) return;\n      document.documentElement.style.overflow = '';\n    }\n\n    function openDrawer(dialog, trigger) {\n      if (!dialog || typeof dialog.showModal !== 'function' || dialog.open) return;\n      lastTrigger = trigger || null;\n      dialog.showModal();\n      // showModal() auto-focuses the first focusable element (the close X), which\n      // shows its focus ring - a stray \"box\" around the X, especially on mobile.\n      // Move initial focus to the panel instead (tabindex=\"-1\", no visible ring);\n      // aria-labelledby still announces the drawer. Keyboard users Tab from here,\n      // so the ring only appears on genuine keyboard navigation.\n      var panel = dialog.querySelector('.drawer__panel');\n      if (panel && typeof panel.focus === 'function') panel.focus();\n      lockScroll();\n    }\n\n    function closeDrawer(dialog) {\n      if (dialog && dialog.open) dialog.close();\n    }\n\n    document.addEventListener('click', function (event) {\n      var trigger = event.target.closest('[data-drawer-trigger]');\n      if (trigger) {\n        var dialog = document.getElementById(trigger.getAttribute('data-drawer-trigger'));\n        if (dialog && typeof dialog.showModal === 'function') {\n          event.preventDefault();\n          openDrawer(dialog, trigger);\n        }\n        return;\n      }\n\n      var closeBtn = event.target.closest('[data-drawer-close]');\n      if (closeBtn) {\n        var owner = closeBtn.closest('dialog.drawer');\n        if (owner && owner.open) owner.close();\n        return;\n      }\n\n      // Overlay / outside click: the click landed on the dialog itself (the\n      // transparent area beside the panel), not on the panel.\n      if (event.target.matches && event.target.matches('dialog.drawer') && event.target.open) {\n        event.target.close();\n      }\n    });\n\n    // close doesn't bubble - listen in the capture phase.\n    document.addEventListener('close', function (event) {\n      var dialog = event.target;\n      if (!dialog.matches || !dialog.matches('dialog.drawer')) return;\n      unlockScroll();\n      if (lastTrigger && typeof lastTrigger.focus === 'function') {\n        lastTrigger.focus();\n      }\n      lastTrigger = null;\n    }, true);\n\n    // Programmatic open/close for any drawer by id (e.g. window.esDrawer.open('cart-drawer')).\n    window.esDrawer = {\n      open: function (id, trigger) {\n        openDrawer(document.getElementById(id), trigger);\n      },\n      close: function (id) {\n        closeDrawer(document.getElementById(id));\n      }\n    };\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"dropdown\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    function root(el) { return el.closest('[data-dropdown]'); }\n\n    function open(node) {\n      node.querySelector('[data-dropdown-trigger]').setAttribute('aria-expanded', 'true');\n      node.querySelector('.dropdown__panel').hidden = false;\n      node.classList.add('dropdown--open');\n    }\n\n    function close(node) {\n      node.querySelector('[data-dropdown-trigger]').setAttribute('aria-expanded', 'false');\n      node.querySelector('.dropdown__panel').hidden = true;\n      node.classList.remove('dropdown--open');\n      clearSearch(node);\n    }\n\n    function clearSearch(node) {\n      var search = node.querySelector('[data-dropdown-search]');\n      if (!search) return;\n      search.value = '';\n      var clearBtn = node.querySelector('[data-dropdown-clear]');\n      if (clearBtn) clearBtn.hidden = true;\n      filter(node, '');\n    }\n\n    function filter(node, query) {\n      var list = node.querySelector('[data-dropdown-list]');\n      var empty = node.querySelector('[data-dropdown-empty]');\n      if (!list) return;\n      var q = query.toLowerCase().trim();\n      var visible = 0;\n      Array.prototype.forEach.call(list.children, function (item) {\n        var match = q === '' || item.textContent.toLowerCase().indexOf(q) !== -1;\n        item.style.display = match ? '' : 'none';\n        if (match) visible++;\n      });\n      if (empty) {\n        /* Setting the text on the aria-live region announces it; clearing it\n           empties the <p> so the global p:empty rule hides it. */\n        empty.textContent = (visible === 0 && q !== '')\n          ? empty.getAttribute('data-no-results') + ' \"' + query + '\"'\n          : '';\n      }\n    }\n\n    function updateValue(node) {\n      var valueEl = node.querySelector('[data-dropdown-value]');\n      if (!valueEl) return;\n      var checked = node.querySelectorAll('[data-dropdown-list] input:checked');\n      var labels = [];\n      Array.prototype.forEach.call(checked, function (input) {\n        var labelSpan = input.closest('label').querySelector('.checkbox__label, .radio__label');\n        if (labelSpan) labels.push(labelSpan.textContent.trim());\n      });\n      if (labels.length) valueEl.textContent = labels.join(', ');\n    }\n\n    document.addEventListener('click', function (e) {\n      var trigger = e.target.closest('[data-dropdown-trigger]');\n      if (trigger) {\n        var node = root(trigger);\n        if (trigger.getAttribute('aria-expanded') === 'true') { close(node); } else { open(node); }\n        return;\n      }\n      if (e.target.closest('[data-dropdown-clear]')) {\n        clearSearch(root(e.target));\n        return;\n      }\n      Array.prototype.forEach.call(document.querySelectorAll('[data-dropdown].dropdown--open'), function (node) {\n        if (!node.contains(e.target)) close(node);\n      });\n    });\n\n    document.addEventListener('input', function (e) {\n      if (!e.target.matches('[data-dropdown-search]')) return;\n      var node = root(e.target);\n      var clearBtn = node.querySelector('[data-dropdown-clear]');\n      if (clearBtn) clearBtn.hidden = !e.target.value;\n      filter(node, e.target.value);\n    });\n\n    document.addEventListener('change', function (e) {\n      var node = root(e.target);\n      if (node && node.matches('[data-dropdown]')) updateValue(node);\n    });\n\n    document.addEventListener('keydown', function (e) {\n      if (e.key !== 'Escape') return;\n      Array.prototype.forEach.call(document.querySelectorAll('[data-dropdown].dropdown--open'), close);\n    });\n\n    function init() {\n      Array.prototype.forEach.call(document.querySelectorAll('[data-dropdown]'), updateValue);\n    }\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', init);\n    } else {\n      init();\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"file-upload\"] && !Shopify.designMode) return;\n  try {\n    document.querySelectorAll('[data-file-upload]').forEach(function (root) {\n    var input = root.querySelector('[data-file-input]');\n    var dropzone = root.querySelector('[data-file-dropzone]');\n    var list = root.querySelector('[data-file-list]');\n    if (!input || !list) return;\n\n    function formatSize(bytes) {\n      if (bytes < 1024) return bytes + ' B';\n      if (bytes < 1048576) return Math.round(bytes / 1024) + ' KB';\n      return (bytes / 1048576).toFixed(1) + ' MB';\n    }\n\n    function render() {\n      list.innerHTML = '';\n      var files = input.files;\n      list.hidden = !files || files.length === 0;\n      Array.prototype.forEach.call(files, function (file) {\n        var li = document.createElement('li');\n        li.className = 'file-upload__item';\n        var name = document.createElement('span');\n        name.className = 'file-upload__name';\n        name.textContent = file.name;\n        var size = document.createElement('span');\n        size.className = 'file-upload__size';\n        size.textContent = formatSize(file.size);\n        var remove = document.createElement('button');\n        remove.type = 'button';\n        remove.className = 'file-upload__remove';\n        remove.setAttribute('aria-label', 'Remove ' + file.name);\n        remove.textContent = '\\u2715';\n        remove.addEventListener('click', function () {\n          input.value = '';\n          render();\n          input.focus();\n        });\n        li.appendChild(name);\n        li.appendChild(size);\n        li.appendChild(remove);\n        list.appendChild(li);\n      });\n    }\n\n    input.addEventListener('change', render);\n\n    if (dropzone) {\n      ['dragenter', 'dragover'].forEach(function (evt) {\n        dropzone.addEventListener(evt, function (e) {\n          e.preventDefault();\n          dropzone.classList.add('is-dragover');\n        });\n      });\n      ['dragleave', 'drop'].forEach(function (evt) {\n        dropzone.addEventListener(evt, function (e) {\n          e.preventDefault();\n          if (evt === 'dragleave' && dropzone.contains(e.relatedTarget)) return;\n          dropzone.classList.remove('is-dragover');\n        });\n      });\n      dropzone.addEventListener('drop', function (e) {\n        if (e.dataTransfer && e.dataTransfer.files.length) {\n          input.files = e.dataTransfer.files;\n          render();\n        }\n      });\n    }\n  });\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"header-account\"] && !Shopify.designMode) return;\n  try {\n    class AccountTooltip extends HTMLElement {\n    connectedCallback() {\n      this.trigger = this.querySelector('[data-account-trigger]');\n      this.panel = this.querySelector('[data-account-panel]');\n      if (!this.trigger || !this.panel) return;\n\n      this.onTriggerClick = this.onTriggerClick.bind(this);\n      this.onDocumentClick = this.onDocumentClick.bind(this);\n      this.onKeydown = this.onKeydown.bind(this);\n\n      this.trigger.addEventListener('click', this.onTriggerClick);\n      document.addEventListener('click', this.onDocumentClick);\n      document.addEventListener('keydown', this.onKeydown);\n    }\n\n    disconnectedCallback() {\n      document.removeEventListener('click', this.onDocumentClick);\n      document.removeEventListener('keydown', this.onKeydown);\n    }\n\n    get open() {\n      return this.hasAttribute('open');\n    }\n\n    set open(value) {\n      if (value) {\n        this.setAttribute('open', '');\n        this.panel.hidden = false;\n        this.trigger.setAttribute('aria-expanded', 'true');\n      } else {\n        this.removeAttribute('open');\n        this.panel.hidden = true;\n        this.trigger.setAttribute('aria-expanded', 'false');\n      }\n    }\n\n    onTriggerClick(event) {\n      event.preventDefault();\n      this.open = !this.open;\n    }\n\n    onDocumentClick(event) {\n      if (!this.open) return;\n      if (this.contains(event.target)) return;\n      this.open = false;\n    }\n\n    onKeydown(event) {\n      if (event.key === 'Escape' && this.open) {\n        this.open = false;\n        this.trigger.focus();\n      }\n    }\n  }\n\n  if (!customElements.get('account-tooltip')) {\n    customElements.define('account-tooltip', AccountTooltip);\n  }\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"header-mega-promo\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    // Promo clips play only while their panel is actually visible.\n    //\n    // The markup deliberately carries no `autoplay` (see the comment beside the\n    // video_tag call): with `autoplay` the browser must fetch media data to\n    // start playback, which defeats `preload=\"none\"` and had every page of the\n    // site downloading the full video source for a promo inside a closed\n    // dropdown. Playback is driven from here instead.\n    //\n    // Visibility is tested rather than inferred from any particular panel's\n    // open state, because the same card renders in two surfaces that hide\n    // themselves differently: the desktop mega panel uses\n    // `opacity: 0; visibility: hidden` (only >=1104px), and the mobile drawer\n    // panel uses `visibility: hidden` at every width. Two checks cover both,\n    // plus any surface added later:\n    //   - computed `visibility` inherits, so an ancestor hiding the panel makes\n    //     the video's own computed value `hidden` without us naming the ancestor;\n    //   - `getClientRects()` is empty under a `display: none` ancestor, which is\n    //     how the mega menu is hidden below 1104px.\n    if (window.__esMegaPromoVideo) return;\n    window.__esMegaPromoVideo = true;\n\n    // Matched structurally rather than by an added class: the stylesheet above\n    // already targets `.header__mega-promo-media video`, so this selector is\n    // guaranteed to hold for as long as the markup does, and it does not depend\n    // on `video_tag` honouring a `class` parameter.\n    var SELECTOR = '.header__mega-promo-media video';\n\n    function isVisible(video) {\n      if (video.getClientRects().length === 0) return false;\n      return window.getComputedStyle(video).visibility !== 'hidden';\n    }\n\n    function sync(root) {\n      var videos = (root || document).querySelectorAll(SELECTOR);\n      Array.prototype.forEach.call(videos, function (video) {\n        if (isVisible(video)) {\n          if (!video.paused) return;\n          var played = video.play();\n          // Muted playback is allowed without a gesture, so a rejection here is\n          // not expected - swallowed the same way the predictive-search category\n          // videos do, so a blocked play never throws into the console.\n          if (played && played.catch) played.catch(function () {});\n        } else if (!video.paused) {\n          video.pause();\n        }\n      });\n    }\n\n    var observer = null;\n\n    // Re-pointed rather than re-registered on section reload: the theme editor\n    // replaces the whole header element, which leaves the old observer watching\n    // a detached node. The document-level listeners below are attached once and\n    // survive, so only the observer needs rebinding.\n    function attach() {\n      var header = document.querySelector('[data-header]');\n      if (!header) return;\n      if (observer) observer.disconnect();\n      // Panels announce themselves by attribute: `open` on <mega-menu>, and\n      // `class`/`inert` on the drawer panels. Watching those on the header\n      // subtree catches every open and close without coupling this to either\n      // controller.\n      observer = new MutationObserver(function () {\n        sync(header);\n      });\n      observer.observe(header, {\n        subtree: true,\n        attributes: true,\n        attributeFilter: ['open', 'class', 'hidden', 'inert'],\n      });\n      sync(header);\n    }\n\n    function init() {\n      attach();\n      // The desktop panel fades, so its computed visibility flips at the end of\n      // the transition rather than when the attribute changes. transitionend\n      // bubbles, so one document-level listener covers every panel.\n      document.addEventListener('transitionend', function (event) {\n        if (event.propertyName === 'visibility' || event.propertyName === 'opacity') sync(document);\n      });\n      // Crossing the 1104px breakpoint swaps which surface is displayed.\n      window.matchMedia('(min-width: 1104px)').addEventListener('change', function () {\n        sync(document);\n      });\n      document.addEventListener('shopify:section:load', attach);\n    }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', init);\n    } else {\n      init();\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"hero-media\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.__esHeroMediaMotion) return;\n    window.__esHeroMediaMotion = true;\n\n    // The videos carry `autoplay` (plus `muted` and `playsinline`) in the\n    // markup, so the browser starts them on its own - the same way every other\n    // site's hero video works. This is only belt and braces for a browser that\n    // has deferred the attribute, and it is unconditional: nothing in here may\n    // decide NOT to play, or it would fight the attribute (#1137).\n    function apply(root) {\n      var videos = (root || document).querySelectorAll('.hero-media__video');\n      Array.prototype.forEach.call(videos, function (v) {\n        if (!v.paused) return;\n        var p = v.play();\n        // One line, so the next person investigating \"the video did not start\"\n        // is not looking at a silent failure the way we were on #1137.\n        if (p && p.catch) {\n          p.catch(function (err) {\n            console.warn('[hero-media] video did not start:', err && err.name ? err.name : err);\n          });\n        }\n      });\n    }\n\n    function init() { apply(document); }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', init);\n    } else {\n      init();\n    }\n    document.addEventListener('shopify:section:load', function (e) { apply(e.target); });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"image-warm\"] && !Shopify.designMode) return;\n  try {\n    // Shared image warming. See the doc header in snippets/image-warm.liquid for\n  // why warming the element (rather than a URL we construct) is what makes the\n  // warmed file provably the one the reveal will use.\n  (function () {\n    if (window.esrWarmImages) return;\n\n    // Two at a time. A six-size product would otherwise open six large\n    // requests at once and starve whatever the shopper is actually looking at.\n    var MAX_IN_FLIGHT = 2;\n    var queue = [];\n    var inFlight = 0;\n\n    function pump() {\n      while (inFlight < MAX_IN_FLIGHT && queue.length) {\n        start(queue.shift());\n      }\n    }\n\n    function start(img) {\n      inFlight++;\n      var done = function () {\n        img.removeEventListener('load', done);\n        img.removeEventListener('error', done);\n        inFlight--;\n        pump();\n      };\n      img.addEventListener('load', done);\n      img.addEventListener('error', done);\n\n      // Layers that withhold their URL (Finishes) hand it over first. The\n      // srcset goes on before the src so the browser picks against `sizes`\n      // rather than fetching the fallback and re-selecting.\n      var srcset = img.getAttribute('data-srcset');\n      if (srcset) {\n        img.setAttribute('srcset', srcset);\n        img.removeAttribute('data-srcset');\n      }\n      var src = img.getAttribute('data-src');\n      if (src) {\n        img.setAttribute('src', src);\n        img.removeAttribute('data-src');\n      }\n\n      // Both paths still need the lazy flip - handing a Finishes layer its src\n      // is not enough while the layer itself is below the fold.\n      //\n      // Order matters: changing `loading` to eager runs the element's lazy load\n      // resumption steps synchronously, and the request reads its priority as\n      // it is created. Set the priority first or it is read too late.\n      img.fetchPriority = 'low';\n      if (img.loading === 'lazy') img.loading = 'eager';\n\n      // An image already in cache fires neither load nor error again.\n      if (img.complete) done();\n    }\n\n    // Start fetching a set of images, cheapest-to-reason-about first: anything\n    // already warmed, already complete, or with nothing to fetch is skipped.\n    window.esrWarmImages = function (imgs) {\n      if (!imgs) return;\n      Array.prototype.forEach.call(imgs, function (img) {\n        if (!img || img.__esWarmed) return;\n        img.__esWarmed = true;\n        if (img.complete && !img.hasAttribute('data-src')) return;\n        queue.push(img);\n      });\n      pump();\n    };\n\n    // Skip speculative warming when the shopper has asked us not to spend their\n    // data. Intent warming ignores this - by then they have asked for the image.\n    function shouldSkipSpeculative() {\n      var c = navigator.connection;\n      if (!c) return false;\n      if (c.saveData) return true;\n      return /^(slow-2g|2g|3g)$/.test(c.effectiveType || '');\n    }\n\n    // Warm as `root` comes within about two screens, then wait for an idle\n    // moment. Deliberately not window.load: on this theme load is dominated by\n    // third parties, so it fires unpredictably and usually while the shopper is\n    // still at the top of the page, where these fetches would compete with the\n    // gallery. Returns a disposer - call it from disconnectedCallback or the\n    // theme editor leaks an observer on every re-render.\n    window.esrWarmWhenNear = function (root, getImgs) {\n      if (!root || shouldSkipSpeculative() || !window.IntersectionObserver) return function () {};\n\n      var observer = new window.IntersectionObserver(function (entries) {\n        if (!entries.some(function (e) { return e.isIntersecting; })) return;\n        observer.disconnect();\n        var run = function () { window.esrWarmImages(getImgs()); };\n        if (window.requestIdleCallback) {\n          // The timeout is not optional - idle periods can be starved\n          // indefinitely inside the theme editor's iframe.\n          window.requestIdleCallback(run, { timeout: 2000 });\n        } else {\n          setTimeout(run, 1000);\n        }\n      }, { rootMargin: '200% 0px' });\n\n      observer.observe(root);\n      return function () { observer.disconnect(); };\n    };\n\n    // Warm what a control is about to reveal, the moment the shopper reaches for\n    // it. Costs nothing speculatively - nothing downloads until they show intent\n    // - and buys 100-500ms on a pointer, 80-150ms on a tap.\n    window.esrWarmOnIntent = function (triggers, resolve) {\n      if (!triggers) return;\n      Array.prototype.forEach.call(triggers, function (trigger) {\n        if (!trigger) return;\n        var warm = function () { window.esrWarmImages(resolve(trigger)); };\n        trigger.addEventListener('pointerenter', warm, { once: true });\n        trigger.addEventListener('focus', warm, { once: true });\n        trigger.addEventListener('touchstart', warm, { once: true, passive: true });\n      });\n    };\n\n    // Sections cannot call the three functions above at connect time. Shopify\n    // emits section JS in compiled_assets/scripts.js and snippet JS in\n    // compiled_assets/snippet-scripts.js, both deferred, and scripts.js is\n    // ordered first - so a section's connectedCallback runs, and its custom\n    // element upgrades, before this file has executed. A section that looked\n    // window.esrWarmWhenNear up at connect would read undefined and silently\n    // never warm anything. Same trap 80beb2be fixed for the ETA module.\n    //\n    // So sections push a registration function onto this queue instead - one\n    // line, no lookup, safe to run before this file exists. Draining it here\n    // and then swapping the array for a run-on-push shim means a section that\n    // connects LATER (the theme editor re-rendering one) registers immediately\n    // rather than sitting in a queue nothing drains again.\n    var queued = window.__esWarmQueue || [];\n    window.__esWarmQueue = { push: function (fn) { fn(); } };\n    queued.forEach(function (fn) { fn(); });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"pagination-nav\"] && !Shopify.designMode) return;\n  try {\n    // Shoppers page with Load more, so the links come out of the layout as soon as\n  // JS is running. Left in the DOM until then (and permanently without JS) so the\n  // deeper pages stay reachable - see the snippet's doc header.\n  //\n  // Managed navs are skipped: their section hides them itself, because it knows\n  // something this file cannot - whether its own pager actually came up.\n  (function () {\n    function hideCrawlNav() {\n      var navs = document.querySelectorAll('[data-pagination-nav]:not([data-pagination-nav-managed])');\n      for (var i = 0; i < navs.length; i++) navs[i].hidden = true;\n    }\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', hideCrawlNav);\n    } else {\n      hideCrawlNav();\n    }\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"predictive-search\"] && !Shopify.designMode) return;\n  try {\n    class PredictiveSearch extends HTMLElement {\n\n    connectedCallback() {\n      this.panel = this.querySelector('[data-predictive-panel]');\n      this.desktopField = this.querySelector('[data-search-field]');\n      this.heading = this.querySelector('.predictive-search__heading');\n      this.idleTitle = this.querySelector('[data-predictive-idle]');\n      this.resultsBar = this.querySelector('[data-predictive-results-heading]');\n      this.noResults = this.querySelector('[data-predictive-no-results]');\n      this.noResultsTitle = this.querySelector('[data-predictive-no-results-title]');\n      this.products = this.querySelector('[data-predictive-products]');\n      this.liveProducts = this.querySelector('[data-ps-products-list]');\n      this.categories = this.querySelector('[data-predictive-categories]');\n      this.suggestionsList = this.querySelector('[data-ps-suggestions]');\n      this.categoriesList = this.querySelector('[data-ps-categories]');\n      /* Read off the group class, not the live list: with \"Show search term\n         suggestions\" off the list isn't rendered at all, and the group still has\n         to be addressable so the results state can collapse the column. */\n      this.suggestionsGroup = this.querySelector('.predictive-search__group--trending');\n      this.categoriesGroup = this.categoriesList ? this.categoriesList.closest('.predictive-search__group') : null;\n      this.asideDivider = this.querySelector('.predictive-search__divider');\n      this.aside = this.querySelector('.predictive-search__aside');\n      this.suggestionsTab = this.querySelector('[data-search-tab=\"trending\"]');\n      this.categoriesTab = this.querySelector('[data-search-tab=\"rooms\"]');\n\n      this.cnstrcToken = 0;\n      this.cnstrcResultId = null;\n      this.currency = (window.Shopify && window.Shopify.currency && window.Shopify.currency.active) || 'AUD';\n\n      // Live results present? Drives hiding of empty live groups in the results\n      // state (e.g. S&D has no query suggestions yet) and the \"no products\"\n      // vs full \"no results\" split.\n      //\n      /* Both aside columns are Constructor-served, and since 11 Sept 2026 both come\n         from the SAME autocomplete response: suggestions from its `Search\n         Suggestions` section (or the popular-searches pod when idle), categories\n         from its `Categories` section. The Shopify path assumes both are present\n         until a\n         response proves otherwise, which is right when the static merchant menus\n         back them. Constructor has no static fallback, so assuming presence would\n         paint an empty Suggestions column on first open - start from nothing and let\n         each response turn its own column on. */\n      /* Merchant switch (header section > Predictive search). While it is off the\n         `hasSuggestions` getter always reads false, so every state rule that hides\n         an empty suggestions column already hides the switched-off one - both data\n         layers, both breakpoints - with no extra branching. */\n      this.suggestionsEnabled = this.getAttribute('data-show-suggestions') !== 'false';\n\n      this.hasSuggestions = !this.cnstrcMode;\n      this.hasCollections = !this.cnstrcMode;\n      this.hasProducts = false;\n      this.viewAll = this.querySelector('[data-ps-view-all]');\n      this.staticEls = Array.prototype.slice.call(this.querySelectorAll('[data-ps-static]'));\n      this.liveEls = Array.prototype.slice.call(this.querySelectorAll('[data-ps-live]'));\n      // Any category card can carry a video. Gated by syncVideo so they only\n      // play while actually on screen (open + no-results state + desktop).\n      this.categoryVideos = this.categories ? Array.prototype.slice.call(this.categories.querySelectorAll('video')) : [];\n      this.status = this.querySelector('[data-predictive-status]');\n      this.tabButtons = Array.prototype.slice.call(this.querySelectorAll('[data-search-tab]'));\n      this.noResultsLabel = this.getAttribute('data-no-results-label') || '';\n      this.noProductsLabel = this.getAttribute('data-no-products-label') || '';\n\n      this.suggestUrl = this.getAttribute('data-suggest-url') || '/search/suggest';\n      this.searchUrl = this.getAttribute('data-search-url') || '/search';\n      this.resultsSection = this.getAttribute('data-results-section') || '';\n\n      /* The merchant's Constructor pods for the idle state (header section settings).\n         An empty string means that pod is switched off: skip the request and keep the\n         Liquid-rendered fallback, never call a pod with a blank id. */\n      this.pods = {\n        products: this.getAttribute('data-pod-products') || '',\n        suggestions: this.getAttribute('data-pod-suggestions') || '',\n      };\n      this.debounceTimer = null;\n      this.controller = null;\n\n      // The mobile trigger is the separate full-width search row in the header.\n      var header = this.closest('.header');\n      this.mobileField = header ? header.querySelector('.header__search--mobile [data-search-field]') : null;\n      this.mobileSearch = this.mobileField ? this.mobileField.closest('[data-search]') : null;\n\n      if (!this.panel || (!this.desktopField && !this.mobileField)) return;\n\n      this.mql = window.matchMedia('(min-width: 1104px)');\n      this.fields = [this.desktopField, this.mobileField].filter(Boolean);\n\n      this.open = this.open.bind(this);\n      this.close = this.close.bind(this);\n      this.onInput = this.onInput.bind(this);\n      this.onKeydown = this.onKeydown.bind(this);\n      this.onDocumentClick = this.onDocumentClick.bind(this);\n      this.onBreakpoint = this.onBreakpoint.bind(this);\n\n      this.fields.forEach(function (field) {\n        field.setAttribute('aria-expanded', 'false');\n        field.setAttribute('aria-controls', this.panel.id);\n        field.addEventListener('focus', this.open);\n        field.addEventListener('click', this.open);\n        field.addEventListener('input', this.onInput);\n      }, this);\n\n      // Close buttons live in each field's .search wrapper (desktop inside this\n      // element, mobile in the external search row).\n      this.closeButtons = Array.prototype.slice.call(document.querySelectorAll('[data-search-close]')).filter(function (btn) {\n        return this.contains(btn) || (this.mobileSearch && this.mobileSearch.contains(btn));\n      }, this);\n      this.closeButtons.forEach(function (btn) {\n        btn.addEventListener('click', function () {\n          // close() returns focus to the active field (the button is hidden on close).\n          this.close();\n        }.bind(this));\n      }, this);\n\n      // Tabs (mobile only; default to the first available group).\n      this.tabButtons.forEach(function (tab) {\n        tab.addEventListener('click', function () {\n          this.activateTab(tab.getAttribute('data-search-tab'));\n        }.bind(this));\n      }, this);\n      if (this.tabButtons.length) {\n        this.activateTab(this.tabButtons[0].getAttribute('data-search-tab'));\n      }\n\n      // Escape is bound at document level so it works whether focus is in the\n      // panel (inside this element) or on the external mobile search field.\n      document.addEventListener('keydown', this.onKeydown);\n      document.addEventListener('click', this.onDocumentClick);\n      this.mql.addEventListener('change', this.onBreakpoint);\n\n      /* Provenance class: makes it obvious in devtools which engine populated the\n         drawer. Set here rather than in Liquid because a param shadows the global\n         settings object in this snippet. */\n      if (this.panel) {\n        this.panel.classList.add(this.cnstrcMode\n          ? 'predictive-search__panel--constructor'\n          : 'predictive-search__panel--shopify');\n      }\n\n      /* Constructor mode hides the idle grid until the pod has been resolved, so the\n         swap to its cards is a fade rather than a flash. Added in JS, not Liquid, so a\n         broken bundle or blocked SDK can never leave the featured collection invisible -\n         without this class the grid paints immediately, which is also what the\n         Shopify-powered drawer always does. */\n      if (this.cnstrcMode && this.products) {\n        this.products.classList.add('predictive-search__cards--pending');\n      }\n\n      /* Constructor: report which autocomplete item was chosen. Delegated on the\n         panel so it covers both the product grid and the suggestion list, and uses\n         mousedown so the event is sent before the navigation starts. */\n      if (this.cnstrcMode && this.panel) {\n        this.panel.addEventListener('mousedown', function (event) {\n          /* The theme's standard product card is what Constructor results render as\n             (hydrated by `esrConstructor.hydrateAll`), and it carries the item\n             attributes this reads. */\n          var card = event.target.closest('.product-card');\n          if (card) {\n            /* Results state only. The same card markup serves the zero state, which is\n               a recommendations container - autotrack derives that click from the\n               container attributes, and a manual autocomplete-select there would file a\n               pod impression as a search interaction. */\n            if (this.getAttribute('data-state') !== 'results') return;\n            this.trackConstructor('trackAutocompleteSelect', card.getAttribute('data-cnstrc-item-name'), {\n              originalQuery: this.currentQuery(),\n              section: 'Products'\n            });\n            return;\n          }\n          var suggestion = event.target.closest('[data-ps-suggestions] a');\n          if (suggestion) {\n            this.trackConstructor('trackAutocompleteSelect', suggestion.textContent.trim(), {\n              originalQuery: this.currentQuery(),\n              section: 'Search Suggestions'\n            });\n          }\n        }.bind(this));\n      }\n\n      this.setState('idle');\n    }\n\n    disconnectedCallback() {\n      document.removeEventListener('keydown', this.onKeydown);\n      document.removeEventListener('click', this.onDocumentClick);\n      if (this.mql) this.mql.removeEventListener('change', this.onBreakpoint);\n      this.abort();\n      this.unlockScroll();\n    }\n\n    get isOpen() {\n      return this.hasAttribute('open');\n    }\n\n    /* Live suggestions present? Stored raw by whichever data layer answered, then\n       gated by the merchant switch on read, so \"switched off\" and \"nothing came\n       back\" are one case for every consumer. */\n    get hasSuggestions() {\n      return this.suggestionsEnabled && this.hasSuggestionsRaw;\n    }\n\n    set hasSuggestions(value) {\n      this.hasSuggestionsRaw = !!value;\n    }\n\n    // Only one field is visible per breakpoint; that one drives the panel.\n    get activeField() {\n      if (this.mql && this.mql.matches) return this.desktopField || this.mobileField;\n      return this.mobileField || this.desktopField;\n    }\n\n    get activeCloseBtn() {\n      var field = this.activeField;\n      if (!field) return null;\n      var wrap = field.closest('[data-search]');\n      return wrap ? wrap.querySelector('[data-search-close]') : null;\n    }\n\n    currentQuery() {\n      var field = this.activeField;\n      return field ? field.value.trim() : '';\n    }\n\n    activateTab(name) {\n      if (!name) return;\n      this.setAttribute('data-active-tab', name);\n      this.tabButtons.forEach(function (tab) {\n        tab.setAttribute('aria-pressed', tab.getAttribute('data-search-tab') === name ? 'true' : 'false');\n      });\n    }\n\n    // If the currently active mobile tab is hidden (its live group is empty),\n    // switch to the first tab that is still visible.\n    ensureVisibleTab() {\n      var active = this.getAttribute('data-active-tab');\n      var current = this.tabButtons.filter(function (t) {\n        return t.getAttribute('data-search-tab') === active;\n      })[0];\n      if (current && !current.hidden) return;\n      var next = this.tabButtons.filter(function (t) { return !t.hidden; })[0];\n      if (next) this.activateTab(next.getAttribute('data-search-tab'));\n    }\n\n    /* Mobile: the fixed panel hangs from the bottom of the SEARCH ROW, which is\n       not always the bottom of the header.\n\n       Once the header collapses, .header__search--mobile is taken out of flow\n       (position: absolute, top: 100%) and slid up behind the bar, so revealing it\n       is a transform rather than a page reflow (#965). The header's own box is\n       then just the bar - around 64px - while the row hangs BELOW that edge. So\n       measuring the header alone placed the panel at the bar's bottom, tucked\n       underneath the very row the shopper had just tapped. At the top of the page\n       the row is still in flow and the header bottom includes it, which is why\n       this only ever went wrong once scrolled (#830).\n\n       Taking whichever edge sits lower is correct in every state: in flow the two\n       agree; collapsed and peeked the row is lower and wins; collapsed and hidden\n       the row sits behind the bar and the bar wins. */\n    setMobileTop() {\n      var header = this.closest('.header');\n      if (!header || !this.panel) return;\n      var bottom = header.getBoundingClientRect().bottom;\n      var row = header.querySelector('.header__search--mobile');\n      if (row) {\n        var rowBottom = row.getBoundingClientRect().bottom;\n        if (rowBottom > bottom) bottom = rowBottom;\n      }\n      // Set on the header so both the panel and the header's page-dim overlay\n      // inherit it (the overlay starts at the same edge on mobile).\n      /* Floored to a whole pixel. A rect bottom is fractional, and a fractional\n         top can leave a hairline of the page showing between the header and the\n         panel; flooring biases the other way, so the panel's edge tucks under\n         the header instead. */\n      header.style.setProperty('--ps-top', Math.floor(Math.max(0, bottom)) + 'px');\n    }\n\n    /* The row slides down over 0.3s, so a measurement taken as search opens\n       describes a position it is still travelling away from, and nothing else\n       would correct it - the transform changes no box size, so a ResizeObserver\n       never fires, and the visual viewport does not move either. Re-measure on\n       the frame after paint, when the transform finishes, and whenever the header\n       changes state, which is what flips the row between hidden and revealed. */\n    trackHeader() {\n      var header = this.closest('.header');\n      if (!header) return;\n      var self = this;\n      this._remeasure = function () { self.setMobileTop(); };\n      requestAnimationFrame(this._remeasure);\n      var row = header.querySelector('.header__search--mobile');\n      if (row) {\n        this._headerRow = row;\n        row.addEventListener('transitionend', this._remeasure);\n      }\n      this._headerObserver = new MutationObserver(this._remeasure);\n      this._headerObserver.observe(header, { attributes: true, attributeFilter: ['class'] });\n    }\n\n    untrackHeader() {\n      if (this._headerObserver) {\n        this._headerObserver.disconnect();\n        this._headerObserver = null;\n      }\n      if (this._headerRow && this._remeasure) {\n        this._headerRow.removeEventListener('transitionend', this._remeasure);\n      }\n      this._headerRow = null;\n      this._remeasure = null;\n    }\n\n    lockScroll() {\n      /* NEVER move the document to lock it. This used to pin the body with\n         `position: fixed; top: -<scrollY>px`, which relaid the page out the\n         instant the field took focus - and iOS Safari drops an in-progress focus\n         when its target is moved out from under the finger. The keyboard never\n         opened and the panel never appeared, so tapping search did nothing. It\n         only showed when the page was scrolled, because at the top `-0px` moves\n         nothing, and only on iOS: every other engine tolerates the relayout.\n         Task #19043403.\n\n         overflow:hidden on <html> alone does NOT hold on iOS - it keeps\n         touch-scrolling the page behind this custom (non-native-dialog) overlay -\n         so swallow touch moves that did not start inside the panel as well. That\n         holds the background still without shifting it by a single pixel. */\n      document.documentElement.style.overflow = 'hidden';\n      /* Advertise the lock, so an overlay that opens ON TOP of search - the\n         range modal, opened from one of the result cards - can tell on its own\n         close that this panel still needs the page held, and leaves the lock\n         alone instead of clearing it out from under an open search (#19502854). */\n      this.setAttribute('data-scroll-locked', '');\n      var self = this;\n\n      /* A gesture is judged once, on its first few pixels, and that verdict holds\n         for the rest of the drag (#830). Two things have to be true for a move to\n         be let through: it started inside something that can actually scroll\n         sideways, and it is going sideways.\n\n         Both halves matter. Exempting the carousel and the tab row by element\n         alone would let a VERTICAL drag that happens to start on a card pan the\n         whole view again, which is the fault Alex just confirmed fixed. Judging\n         by axis alone would exempt sideways drags over content that cannot\n         scroll, for no benefit. Together: horizontal swipes on the strips work,\n         everything vertical stays dead.\n\n         The scroller is found by measuring at touchstart rather than by matching\n         class names - scrollWidth against clientWidth is true of a real scroller\n         whatever it is called, so this does not rot when the markup changes. The\n         verdict is latched so a swipe that drifts off-axis mid-flick does not\n         suddenly hand the page back to iOS. */\n      this._hScroller = function (node) {\n        var el = node;\n        while (el && el !== self.panel && el.nodeType === 1) {\n          if (el.scrollWidth > el.clientWidth + 1) {\n            var ox = window.getComputedStyle(el).overflowX;\n            if (ox === 'auto' || ox === 'scroll') return el;\n          }\n          el = el.parentElement;\n        }\n        return null;\n      };\n\n      this._onTouchStart = function (e) {\n        var t = e.touches && e.touches[0];\n        self._gesture = t\n          ? { x: t.clientX, y: t.clientY, scroller: self._hScroller(e.target), axis: null, exempt: false, blurred: false }\n          : null;\n      };\n\n      this._onTouchEnd = function () {\n        self._gesture = null;\n        self.resetDrawerScrollIfPending();\n      };\n\n      this._onTouchMove = function (e) {\n        /* ANY finger movement dismisses the keyboard. Not a scroll event, not a\n           visual-viewport event - the touch itself.\n\n           Both of those were tried and neither caught it on the device. The\n           panel's scroll event does not fire when the BROWSER pans rather than\n           the panel; the visual viewport's own scroll event did not reach us\n           either. A touchmove cannot miss: whatever is moving - the page, the\n           browser's own viewport, or nothing at all - the finger moved, and that\n           is the thing being detected.\n\n           It also removes the need for the machinery that came before it. A\n           keyboard opening produces no touchmove, because no finger moved, so\n           there is nothing to tell apart and no grace window to tune: the\n           previous version needed 600ms of it purely to avoid dismissing the\n           keyboard on the pan the keyboard itself caused.\n\n           Threshold, not first pixel, so a tap that trembles does not count.\n           Once per gesture, and blur only - no scroll call in the same frame,\n           which is what invites Safari to pan again. */\n        var g0 = self._gesture;\n        var t0 = e.touches && e.touches[0];\n        if (g0 && t0) {\n        }\n        if (g0 && t0 && !g0.blurred) {\n          if (Math.abs(t0.clientX - g0.x) > 12 || Math.abs(t0.clientY - g0.y) > 12) {\n            g0.blurred = true;\n            var focused = document.activeElement;\n            if (focused && self._ownsField && self._ownsField(focused) && typeof focused.blur === 'function') {\n              if (focused.matches('input, textarea')) {\n                focused.blur();\n              }\n            }\n          }\n        }\n\n        /* Panel-origin moves are swallowed too (#830). This used to exempt them\n           so the panel could scroll its own results - but the panel is no longer\n           scrollable, so the exemption stopped buying anything and instead handed\n           iOS the one gesture it uses to pan: a drag starting inside the overlay\n           with nothing to consume it panned the whole rendered view, page and\n           header and all, however well the document itself was held. With the\n           move cancelled there is nothing for the pan to ride on.\n           Taps are untouched - this is touchmove only, so buttons, links and the\n           cards all still work normally. */\n        /* A modal dialog is in the top layer, which is ABOVE this overlay, not\n           behind it - so it is not part of \"the page\" this lock holds still.\n           Cancelling its touches froze the range modal opened from a result\n           card: its product strip could not be swiped at all (#19502854). */\n        if (e.target && e.target.closest && e.target.closest('dialog[open]')) return;\n        var g = self._gesture;\n        var t = e.touches && e.touches[0];\n\n        /* A gesture that began inside a genuine horizontal scroller is handed to\n           the browser, and crucially is NOT cancelled while we work out which way\n           it is going.\n\n           That waiting period was the bug Alex hit as \"it works, but takes a few\n           attempts\". The axis used to be latched once the finger had travelled a\n           few pixels, and until then every move was cancelled - but cancelling\n           the OPENING move of a gesture makes the browser abandon native\n           scrolling for the whole of it. So a swipe only took if its very first\n           sampled move was already flat and fast; an ordinary thumb swipe, which\n           starts slow and slightly downward, was killed before it began and had\n           to be repeated until one happened to start flat enough.\n\n           Nothing needs to be measured now anyway: touch-action: pan-x on the\n           strip lets the browser permit sideways panning and forbid vertical, so\n           the page cannot move whichever way the finger goes.\n\n           The check below is only a fallback for an engine that ignores\n           touch-action. It waits for a drag that is unmistakably vertical, which\n           keeps it clear of any sideways swipe, and by then the scroll decision\n           has long been made so being late costs nothing. */\n        /* The panel body scrolls now, so a drag that starts inside the panel is\n           the shopper scrolling their results - not the page-pan this handler was\n           written to stop. It is left alone, and the page behind is held by\n           overflow:hidden on <html> plus overscroll-behavior on the panel, which\n           is what stops the scroll chaining out at either end.\n\n           Everything OUTSIDE the panel is still swallowed, which is the part\n           that mattered: that is the drag that used to move the whole view. */\n        /* HARD LOCK, restored. Only a touch inside the drawer - the one element\n           allowed to scroll - is let through. Everything else is swallowed,\n           including a drag on the panel outside the drawer, which is what used\n           to let the browser take the whole view.\n\n           v1 exempted the whole panel and that was too generous: the panel is\n           the fixed frame, so a drag on it had nothing to scroll and went\n           straight to the browser. */\n        var drawer = self.querySelector('.predictive-search__drawer');\n        if (drawer && drawer.contains(e.target)) return;\n\n        if (g && g.scroller && t) {\n          var sx = Math.abs(t.clientX - g.x);\n          var sy = Math.abs(t.clientY - g.y);\n          if (sy > 24 && sy > sx * 2) {\n            e.preventDefault();\n            return;\n          }\n          return;\n        }\n\n        // Everywhere else in the panel there is nothing to scroll, so every move\n        // is still swallowed outright - that is what holds the page still.\n        e.preventDefault();\n      };\n      document.addEventListener('touchstart', this._onTouchStart, { passive: true });\n      document.addEventListener('touchend', this._onTouchEnd, { passive: true });\n      document.addEventListener('touchcancel', this._onTouchEnd, { passive: true });\n      document.addEventListener('touchmove', this._onTouchMove, { passive: false });\n      this.trackViewport();\n    }\n\n    /* The keyboard does not change the LAYOUT viewport, it shrinks and pans the\n       VISUAL one. Everything here is position:fixed, which anchors to the layout\n       viewport, so with the keyboard up the panel and the scrim keep their old\n       geometry and the whole composition slides under a smaller window: the scrim\n       edge drifts inward, anything fixed to the bottom lands mid-screen, and the\n       header pans off the top (#19449070).\n\n       No CSS length fixes this. vh, svh, lvh and dvh all describe the layout\n       viewport and the browser's own chrome - none of them shrink for a keyboard.\n       window.visualViewport is the only thing that reports the real visible\n       rectangle, so it is published as custom properties for the CSS to use.\n\n       Deliberately ONLY sets custom properties. It does not move, resize or\n       reflow the document: doing that during focus is what broke search outright\n       on iOS before (task #19043403 - the body was pinned with position:fixed,\n       the page relaid out the instant the field took focus, and iOS drops an\n       in-progress focus when its target moves out from under the finger, so the\n       keyboard never opened). Custom properties are safe because they change\n       nothing about the document's own box. */\n    /* Item 8: the keyboard gets out of the way on a tap or a scroll inside the\n       panel. Blurring the field is what dismisses it - there is no API to close\n       the keyboard directly - so the field is only blurred, never re-focused,\n       and the panel stays open either way.\n\n       A tap on something interactive is left alone: tapping a suggestion should\n       follow it, and tapping the field itself obviously must not dismiss the\n       keyboard the tap just asked for. The scroll listener is passive, so it can\n       never delay the scroll it is watching. */\n    /* Return the drawer to the top after a scroll has dismissed the keyboard.\n\n       While the keyboard is up the drawer is capped short, so a small scroll\n       reaches lower content. When the dismissal drops the keyboard the cap\n       releases and the drawer grows, but it keeps the offset from the gesture -\n       leaving the heading and the first row of chips cut off above the top edge\n       of a drawer that may no longer overflow at all.\n\n       Deferred, not immediate, on two conditions. The finger may still be down,\n       since the gate that fixed the reopen loop lets a dismissal fire mid-drag,\n       and writing scrollTop under a live gesture fights the scroll still in\n       flight. And the keyboard may not have finished leaving, so the cap has\n       not released yet. Both are checked here rather than guessed at with a\n       timer, and this runs from both the viewport settling and the finger\n       lifting, because either can happen last.\n\n       Smooth, per the client. The deferral is what makes that safe - see the\n       note at the call itself. */\n    resetDrawerScrollIfPending() {\n      if (!this._pendingScrollReset) return;\n      if (this._gesture) return;\n      var vv = window.visualViewport;\n      if (vv && Math.abs(vv.height - window.innerHeight) > 2) return;\n      var drawer = this._dismissScroller || this.querySelector('.predictive-search__drawer');\n      if (drawer) {\n        /* Smooth, which the deferral above is what makes safe: by the time this\n           runs the keyboard has gone and the finger is up, so the animation has\n           nothing left to fight and no collapse to stutter against.\n\n           Feature-detected rather than assumed. Safari honours behavior:smooth\n           on an element from 15.4; older engines ignore the options object and\n           read the call as scrollTo(x, y), which lands somewhere unintended, so\n           they take the plain assignment instead. */\n        if ('scrollBehavior' in document.documentElement.style && typeof drawer.scrollTo === 'function') {\n          drawer.scrollTo({ top: 0, behavior: 'smooth' });\n        } else {\n          drawer.scrollTop = 0;\n        }\n      }\n      this._pendingScrollReset = false;\n    }\n\n    trackKeyboardDismiss() {\n      if (!this.panel) return;\n      var self = this;\n      var field = this.mobileField || this.desktopField;\n\n      /* THE FAULT ALL SIX ROUNDS DIED ON. The mobile search field is not inside\n         this element: the header renders `.header__search--mobile` as a sibling\n         of <predictive-search>, so on mobile document.activeElement is outside\n         it and `self.contains(active)` is false for the only field a shopper\n         ever types into there. Every dismissal path was gated on that test, so\n         none of them could ever fire on a phone - which is why the readout\n         showed hundreds of touchmoves and scrolls arriving while dismissals\n         stayed at zero. Nothing was being suppressed; the guard was rejecting\n         its own field.\n\n         The keyboard going away on a tap was iOS doing it natively, not us.\n\n         The rest of the file already knew this - the refocus check pairs the\n         element with mobileSearch - so this uses the same idiom rather than\n         inventing a second one. */\n      this._ownsField = function (el) {\n        if (!el) return false;\n        if (self.contains(el)) return true;\n        return !!(self.mobileSearch && self.mobileSearch.contains(el));\n      };\n\n      this._dismissKeyboard = function (event) {\n        var active = document.activeElement;\n        if (!active || typeof active.blur !== 'function') return;\n        if (!self._ownsField(active)) return;\n        if (event && event.type === 'click') {\n          if (event.target.closest('a, button, input, textarea, select, [role=\"button\"], [role=\"tab\"]')) return;\n        }\n        active.blur();\n        /* Only when movement dismissed it. A tap is left alone deliberately:\n           the shopper may have scrolled to something earlier and then tapped to\n           put the keyboard away, and yanking them back to the top would throw\n           away a position they chose. Movement-driven dismissal is the case\n           where the drawer is left holding a mid-gesture offset it was never\n           asked for. */\n        if (!event || event.type !== 'click') self._pendingScrollReset = true;\n      };\n\n      /* THE DOCUMENT SCROLLED. Of everything tried to catch the moment the view\n         moves under an open keyboard, this is the one signal never wired up: the\n         panel's own scroll fires only when the panel scrolls (and since the\n         scroller moved to the drawer, not even then), visualViewport's scroll\n         never arrived, and touchmove may never reach us. But when Safari enters\n         keyboard mode it scrolls the LAYOUT viewport to keep the input reachable,\n         and a layout-viewport scroll is reported on window like any other.\n\n         Threshold, not zero: iOS settles the scroll position by a pixel or two\n         when the keyboard animates in, and that must not read as the shopper\n         moving the page. Once past it we drop the keyboard, Safari leaves\n         keyboard mode, and the lock we already have resumes control - which is\n         the whole point. No geometry correction, just end the mode. */\n      this._scrollBase = null;\n      this._onWindowScroll = function () {\n        /* Only while a finger is actually on the glass. See the note on the\n           drawer's scroll listener below - the keyboard's own arrival moves\n           things with nobody touching the screen. */\n        if (!self._gesture) return;\n        var y = window.pageYOffset || document.documentElement.scrollTop || 0;\n        if (self._scrollBase === null) self._scrollBase = y;\n        if (Math.abs(y - self._scrollBase) <= 4) return;\n        var active = document.activeElement;\n        if (!active || !self._ownsField(active) || typeof active.blur !== 'function') return;\n        if (!active.matches('input, textarea')) return;\n        active.blur();\n        /* Safari restores the viewport as the keyboard goes; --ps-top was read\n           from a rect taken mid-pan, so re-seat the panel under the header once\n           that has happened rather than leaving the gap behind. */\n        window.requestAnimationFrame(function () {\n          self.setMobileTop();\n        });\n      };\n      window.addEventListener('scroll', this._onWindowScroll, { passive: true });\n      document.addEventListener('scroll', this._onWindowScroll, { passive: true, capture: true });\n\n      this.panel.addEventListener('click', this._dismissKeyboard);\n      /* v6 moved the scroller from the panel to the drawer, which left this\n         listener on an element that can no longer scroll. Follow the scroller. */\n      this._dismissScroller = this.querySelector('.predictive-search__drawer') || this.panel;\n      /* A scroll only dismisses when a finger is driving it.\n\n         Without this, refocusing the field could not raise the keyboard: the\n         keyboard arrives, the visual viewport shrinks, the drawer's height cap\n         shrinks with it, and the reflow moves the scroll position - which the\n         scroll listener read as the shopper scrolling and answered by\n         dismissing the keyboard that had just opened. The keyboard flashed and\n         vanished. The loop only became possible once the dismissal started\n         working at all.\n\n         _gesture is set on touchstart and cleared on touchend, so it says\n         plainly whether a finger is down. No timers and no grace window: a\n         delay would only have raced the same reflow, and the finger is the\n         real distinction rather than an approximation of it.\n\n         Desktop consequence, deliberate: scrolling the results with a mouse no\n         longer blurs the field. There is no on-screen keyboard to dismiss\n         there, which is the only thing this ever existed to do. */\n      this._onScrollerScroll = function (event) {\n        if (!self._gesture) return;\n        self._dismissKeyboard(event);\n      };\n      this._dismissScroller.addEventListener('scroll', this._onScrollerScroll, { passive: true });\n\n      /* And the same dismissal from the drag itself. Tapping in the drawer\n         already hides the keyboard, but scrolling did not, and the scroll event\n         above cannot be relied on: the drawer only became scrollable at all in\n         the previous build, and on this device scroll-shaped signals have a\n         history of not arriving. A finger moving inside the drawer is the plain\n         fact underneath both, so it drives the same handler.\n\n         Passive, so the drawer keeps scrolling natively while the keyboard\n         goes. The threshold is above tap jitter deliberately: a tap that lands\n         on a product link is dismissed by the click path, which exempts links,\n         and blurring on a few pixels of wobble would collapse the keyboard\n         mid-tap and move the link out from under the finger. */\n      this._onDrawerDrag = function (e) {\n        var g = self._gesture;\n        var t = e.touches && e.touches[0];\n        if (!g || !t) return;\n        if (Math.abs(t.clientX - g.x) < 8 && Math.abs(t.clientY - g.y) < 8) return;\n        self._dismissKeyboard(e);\n      };\n      this._dismissScroller.addEventListener('touchmove', this._onDrawerDrag, { passive: true });\n\n\n      if (field) this._dismissField = field;\n    }\n\n    untrackKeyboardDismiss() {\n      this._pendingScrollReset = false;\n      if (!this.panel || !this._dismissKeyboard) return;\n      this.panel.removeEventListener('click', this._dismissKeyboard);\n      if (this._dismissScroller) {\n        this._dismissScroller.removeEventListener('scroll', this._onScrollerScroll, { passive: true });\n        this._onScrollerScroll = null;\n        if (this._onDrawerDrag) {\n          this._dismissScroller.removeEventListener('touchmove', this._onDrawerDrag, { passive: true });\n          this._onDrawerDrag = null;\n        }\n        this._dismissScroller = null;\n      }\n      if (this._onWindowScroll) {\n        window.removeEventListener('scroll', this._onWindowScroll, { passive: true });\n        document.removeEventListener('scroll', this._onWindowScroll, { passive: true, capture: true });\n        this._onWindowScroll = null;\n      }\n      this._scrollBase = null;\n      this._dismissKeyboard = null;\n    }\n\n    trackViewport() {\n      var vv = window.visualViewport;\n      if (!vv) return; // no support: falls back to the dvh values in the CSS\n      var root = document.documentElement;\n      var self = this;\n      this._onViewport = function () {\n        /* A pan can leave the visual viewport offset while the layout viewport\n           has not moved. If the keyboard then dismisses, the compensation values\n           describe a state that no longer exists and the composition comes back\n           in pieces - header detached, panel fragments in the wrong place\n           (#830). So when the visible height returns to roughly the full window\n           the keyboard has gone: clear the offset outright rather than trusting\n           a reading taken mid-pan, and re-measure the header, since --ps-top was\n           captured from a rect that was itself panned. */\n        /* Height alone cannot tell us the keyboard is up. On iOS the URL bar\n           collapses as soon as the page is scrolled, which shrinks the visual\n           viewport WITHOUT any keyboard - the two only agree at the very top of\n           the page. Treating that as a keyboard fed vv.offsetTop into the panel's\n           top offset and skipped the header re-measure, so with the page scrolled\n           the panel was pushed away from the header and out of view, and it came\n           right again only when scrolled back to the top.\n           The keyboard is therefore identified by what actually raises it: focus\n           sitting in the search field. Height is still required as well, so a\n           focused field with no keyboard (a hardware keyboard, or the moment\n           before it animates in) does not offset anything. */\n        var active = document.activeElement;\n        var typing = active && self.contains(active) && active.matches('input, textarea');\n        var shrunk = Math.abs(vv.height - window.innerHeight) > 2;\n        var keyboard = shrunk && typing;\n\n        root.style.setProperty('--vv-height', vv.height + 'px');\n        /* Kept for the debug readout only - nothing lays out against it now. */\n        root.style.setProperty('--vv-offset', keyboard ? vv.offsetTop + 'px' : '0px');\n        // Re-measure whenever the keyboard is NOT the thing moving the viewport,\n        // which now includes an ordinary scroll: the header condenses as the page\n        // moves, so its bottom edge - the panel's anchor - has to be read again.\n        if (!keyboard) self.setMobileTop();\n        self.resetDrawerScrollIfPending();\n      };\n      this._onViewport();\n      vv.addEventListener('resize', this._onViewport);\n      vv.addEventListener('scroll', this._onViewport);\n    }\n\n    untrackViewport() {\n      var vv = window.visualViewport;\n      if (vv && this._onViewport) {\n        vv.removeEventListener('resize', this._onViewport);\n        vv.removeEventListener('scroll', this._onViewport);\n      }\n      this._onViewport = null;\n      // Cleared rather than left behind, so the fallbacks apply once search is\n      // shut and nothing else on the page inherits a stale keyboard height.\n      document.documentElement.style.removeProperty('--vv-height');\n      document.documentElement.style.removeProperty('--vv-offset');\n    }\n\n    unlockScroll() {\n      this.untrackKeyboardDismiss();\n      this.untrackHeader();\n      this.untrackViewport();\n      document.documentElement.style.overflow = '';\n      this.removeAttribute('data-scroll-locked');\n      if (this._onTouchStart) {\n        document.removeEventListener('touchstart', this._onTouchStart, { passive: true });\n        document.removeEventListener('touchend', this._onTouchEnd, { passive: true });\n        document.removeEventListener('touchcancel', this._onTouchEnd, { passive: true });\n        this._onTouchStart = null;\n        this._onTouchEnd = null;\n      }\n      this._gesture = null;\n      if (this._onTouchMove) {\n        document.removeEventListener('touchmove', this._onTouchMove, { passive: false });\n        this._onTouchMove = null;\n      }\n    }\n\n    open() {\n      // Re-entrancy guard: returning focus to the field on close fires a focus\n      // event; this stops that from re-opening the panel.\n      if (this._suppressOpen) return;\n      if (this.isOpen) {\n        this.syncControls();\n        return;\n      }\n      if (!this.mql.matches) {\n        this.setMobileTop();\n        this.trackHeader();\n        this.trackKeyboardDismiss();\n        this.lockScroll();\n        // Mobile: the full-screen drawer is a modal dialog so AT treats the\n        // obscured page behind it as inert (mirrors the menu-drawer).\n        this.panel.setAttribute('role', 'dialog');\n        this.panel.setAttribute('aria-modal', 'true');\n      }\n      this.setAttribute('open', '');\n      /* Publish the overlay's presence on <html> so anything pinned to the\n         viewport can get out of its way - the Zendesk launcher is the first,\n         and it owns its own rule in snippets/zendesk-widget. Same contract the\n         sticky add-to-cart and collection filter bars already use: the feature\n         raises the flag and is responsible for clearing it again.\n\n         The theme's other overlays are showModal() dialogs, which the browser\n         promotes to the top layer, so they cover the launcher whatever its\n         z-index and need no flag. This overlay is a plain element toggling an\n         open attribute, so nothing stacks it above the launcher for us. */\n      document.documentElement.classList.add('search-open');\n      var field = this.activeField;\n      if (field) field.setAttribute('aria-expanded', 'true');\n\n      /* Constructor: popular searches replace the merchant's trending menu, and the\n         beacon wants to know the field was focused. Both are one-per-page. */\n      if (this.cnstrcMode) {\n        this.primeConstructorSuggestions();\n        this.trackConstructor('trackInputFocus', this.currentQuery());\n      }\n\n      this.handleQuery();\n      this.syncControls();\n    }\n\n    /* Fills the idle state from Constructor: popular searches in the suggestion\n       slot, and the product-suggestions pod over the theme's featured collection, so\n       the drawer shows engine content before a term is typed. Once per page. */\n    primeConstructorSuggestions() {\n      if (this.cnstrcPrimed) return;\n      this.cnstrcPrimed = true;\n      this.restoreConstructorSuggestions();\n      this.primeConstructorFeatured();\n    }\n\n    /* Replaces the server-rendered featured product cards with the pod's, so the\n       idle grid is Constructor-driven too. Left alone if the pod is switched off or\n       returns nothing, so an unset or unpopulated pod degrades to the merchant's\n       featured collection rather than an empty drawer.\n\n       Constructor calls this the zero state, and it is a RECOMMENDATIONS surface, not\n       an autosuggest one - the items come from a pod, not from a query. So the\n       container takes the recommendations attributes and the cards are recommendation\n       items. They keep item-section as well, which the spec asks for on exactly this\n       case: a pod powering zero-state autosuggest results. The attributes are set here\n       rather than in Liquid so they exist only when the pod really served the cards;\n       the merchant's featured collection stays untagged. */\n    primeConstructorFeatured() {\n      if (!this.products) return;\n      var self = this;\n      var pod = this.pods.products;\n      if (!pod) {\n        this.settleFeatured();\n        return;\n      }\n      window.esrConstructor.load().then(function (client) {\n        if (!client) return;\n        return client.recommendations\n          .getRecommendations(pod, {\n            numResults: 4,\n            section: 'Products'\n          })\n          .then(function (res) {\n            var items = (res && res.response && res.response.results) || [];\n            if (!items.length) return;\n            /* The pod's items become the theme's standard cards, rendered by Liquid -\n               one request each, so this resolves a beat after the pod does. The\n               merchant's server-rendered featured collection stays in place until they\n               land, and is left alone entirely if none of them render. */\n            return window.esrConstructor\n              .hydrateAll(items, { section: 'Products', recommendation: true })\n              .then(function (rows) {\n                if (!rows.length) return;\n                self.products.innerHTML = '';\n                rows.forEach(function (row) { self.products.appendChild(row.el); });\n                window.esrConstructor.initInjectedCards();\n                window.esrConstructor.tagRecommendations(self.products, {\n                  podId: pod,\n                  resultId: res.result_id,\n                  // Response total, not the four asked for. Unseeded: the zero state has\n                  // no item to work from.\n                  numResults: res.response && res.response.total_num_results\n                });\n                /* The pod can resolve after the shopper has already typed, and the\n                   container attributes must not be live outside the zero state.\n                   Re-running the current state parks them if so. */\n                self.setState(self.getAttribute('data-state') || 'idle');\n              });\n          });\n      })\n        .catch(function () {})\n        /* Runs on every outcome - cards injected, empty pod, 404, dead SDK - because\n           the grid stays invisible until the choice between the pod's cards and the\n           merchant's featured collection has actually been made. */\n        .then(function () { self.settleFeatured(); });\n    }\n\n    /* Reveals the idle grid, fading it in. In Constructor mode the grid starts\n       transparent, so the pod replacing the server-rendered featured collection is one\n       fade rather than a flash of one set of cards followed by another. Whichever set\n       wins, it fades in once - and a pod that answers before the drawer is opened has\n       already settled, so there is no fade at all. */\n    settleFeatured() {\n      if (this.products) this.products.classList.remove('predictive-search__cards--pending');\n    }\n\n    restoreConstructorSuggestions() {\n      var self = this;\n      var token = this.cnstrcToken;\n\n      /* Results are query-scoped, so clear them on the way back to idle. Leaving\n         them would keep tagged items in the DOM that the shopper cannot see. */\n      if (this.categoriesList) this.categoriesList.innerHTML = '';\n      if (this.liveProducts) this.liveProducts.innerHTML = '';\n      this.hasCollections = false;\n      this.hasProducts = false;\n\n      this.fetchConstructorSuggestions().then(function (suggestions) {\n        // A query typed while this was in flight wins.\n        if (token !== self.cnstrcToken) return;\n        // Pod-served, so these render as recommendation items.\n        self.renderSuggestions(suggestions, true);\n        self.hasSuggestions = suggestions.length > 0;\n        /* The list is the zero state's second recommendations container, alongside the\n           product grid. Tagged only when the pod actually returned terms, so an empty\n           pod leaves it untagged and the aside falls back to the merchant's menus. */\n        if (suggestions.length && self.suggestionsList) {\n          window.esrConstructor.tagRecommendations(self.suggestionsList, self.cnstrcSuggestionsMeta || {});\n        }\n        // The pod resolves after setState has already run, so re-apply visibility.\n        self.setState(self.getAttribute('data-state') || 'idle');\n      });\n    }\n\n    /* Fire-and-forget tracker call. Never allowed to throw into the drawer, and a\n       no-op when the SDK is unavailable. */\n    trackConstructor(method, term, extra) {\n      if (!this.cnstrcMode) return;\n      var self = this;\n      window.esrConstructor.load().then(function (client) {\n        if (!client || !client.tracker || typeof client.tracker[method] !== 'function') return;\n        var params = extra || {};\n        if (self.cnstrcResultId) params.resultId = self.cnstrcResultId;\n        try {\n          if (term == null) client.tracker[method](params);\n          else client.tracker[method](term, params);\n        } catch (e) {}\n      }).catch(function () {});\n    }\n\n    close() {\n      if (!this.isOpen) return;\n      // If focus is anywhere within the overlay (panel content or a control that\n      // is about to hide), return it to the active field on close (WCAG 2.4.3).\n      var active = document.activeElement;\n      var refocus = this.contains(active) || (this.mobileSearch && this.mobileSearch.contains(active));\n\n      this.abort();\n      this.removeAttribute('open');\n      // Cleared here, and only here: every close path - Escape, the backdrop,\n      // the mobile dismiss - funnels through this method, and the open\n      // attribute is removed in exactly one place, so the flag cannot be\n      // stranded by a route that skips it.\n      document.documentElement.classList.remove('search-open');\n      this.fields.forEach(function (field) {\n        field.setAttribute('aria-expanded', 'false');\n        // Closing also clears the query. Set the value directly (dispatching an\n        // input event would re-open the overlay) and keep each field's own Clear\n        // button in sync since we changed the value programmatically.\n        field.value = '';\n        var wrap = field.closest('[data-search]');\n        var clearBtn = wrap ? wrap.querySelector('[data-search-clear]') : null;\n        if (clearBtn) clearBtn.hidden = true;\n      });\n      this.panel.setAttribute('role', 'region');\n      this.panel.removeAttribute('aria-modal');\n      this.unlockScroll();\n      this.closeButtons.forEach(function (btn) {\n        btn.hidden = true;\n      });\n      this.setState('idle');\n\n      if (refocus) {\n        var field = this.activeField;\n        if (field) {\n          if (this.mql.matches) {\n            // Desktop: return focus to the field (WCAG 2.4.3); guarded so the\n            // focus event doesn't re-open the overlay.\n            this._suppressOpen = true;\n            field.focus();\n            this._suppressOpen = false;\n          } else {\n            // Mobile: blur to dismiss the keyboard. Refocusing would re-open the\n            // overlay (focus opens search) and iOS fires that focus async, so the\n            // open guard can't catch it.\n            if (active && active.blur) active.blur();\n          }\n        }\n      }\n    }\n\n    onInput() {\n      if (!this.isOpen) this.open();\n      this.syncControls();\n      this.handleQuery();\n    }\n\n    onKeydown(event) {\n      if (event.key === 'Escape' && this.isOpen) this.close();\n    }\n\n    onDocumentClick(event) {\n      if (!this.isOpen) return;\n      if (this.contains(event.target)) return;\n      if (this.mobileSearch && this.mobileSearch.contains(event.target)) return;\n      this.close();\n    }\n\n    onBreakpoint() {\n      // The active field + layout change across the breakpoint; close cleanly.\n      this.close();\n    }\n\n    // Empty field -> idle (static aside + featured). A query debounces a native\n    // fetch; the state flips to results / no-results once it resolves, so the\n    // idle content stays put (no empty flash) while the request is in flight.\n    handleQuery() {\n      var query = this.currentQuery();\n      if (!query) {\n        this.abort();\n        /* Constructor: clearing the field drops back to popular searches, replacing\n           the query suggestions the last search left in the list. Cached, so this\n           costs nothing after the first fetch. */\n        if (this.cnstrcMode) {\n          this.cnstrcToken++;\n          this.restoreConstructorSuggestions();\n        }\n        this.setState('idle');\n        return;\n      }\n      var self = this;\n      clearTimeout(this.debounceTimer);\n      this.debounceTimer = setTimeout(function () {\n        self.fetchResults(query);\n      }, 250);\n    }\n\n    abort() {\n      clearTimeout(this.debounceTimer);\n      if (this.controller) {\n        this.controller.abort();\n        this.controller = null;\n      }\n    }\n\n    /* True when Constructor is enabled and keyed. In that mode Shopify Search &\n       Discovery is not consulted at all. */\n    get cnstrcMode() {\n      return this.hasAttribute('data-cnstrc-search-engine') && !!window.esrConstructor;\n    }\n\n    /* Constructor's autocomplete replaces both Shopify requests. Products come from\n       the Products section; the suggestion list is a separate recommendations pod\n       (Constructor's own \"Search Suggestions\" autocomplete section is not what powers\n       it). The autocomplete failure is swallowed so a Constructor outage leaves the\n       drawer empty rather than broken: `res` comes back null, all three sections\n       read empty, and the drawer lands on 'no-results' with the popular-searches\n       aside. Note the single call means categories now share that fate - but they\n       already would have, since a term with no products and no suggestions was\n       going to 'no-results' regardless. */\n    fetchResultsFromConstructor(query) {\n      var self = this;\n      var token = ++this.cnstrcToken;\n\n      window.esrConstructor.load().then(function (client) {\n        if (!client || token !== self.cnstrcToken) return;\n\n        /* ONE call. Autocomplete now carries the category column too, in a\n           `Categories` section Constructor curate in the index, so the second\n           request (a one-row `getSearchResults` read only for its group counts) is\n           gone - two network calls per keystroke become one.\n\n           ALL THREE sections must be named in `resultsPerSection`. Naming one\n           suppresses the rest: asking for Categories alone returns\n           `{ Products: 0, 'Search Suggestions': 0, Categories: 5 }` - verified\n           against the AU index on 11 Sept 2026. Omitting the option entirely gives\n           Constructor's own defaults (3/3/4), which is not what the layout wants. */\n        return client.autocomplete\n          .getAutocompleteResults(query, {\n            resultsPerSection: {\n              Products: 4,\n              'Search Suggestions': 6,\n              Categories: 5\n            }\n          })\n          .catch(function () { return null; })\n          .then(function (res) {\n            if (token !== self.cnstrcToken) return;\n            var sections = (res && res.sections) || {};\n            self.cnstrcResultId = (res && res.result_id) || null;\n            self.renderConstructorResults(\n              query,\n              sections.Products || [],\n              sections['Search Suggestions'] || [],\n              self.constructorCategories(sections.Categories)\n            );\n          });\n      });\n    }\n\n    /* Popular searches, fetched once per page and reused. Query-independent, so the\n       same list serves the idle and results states. Resolves to an empty list when the\n       pod setting is blank - no request is made with an empty id - which lands on the\n       same fallback as a 404 or an empty pod: the merchant's Trending / Browse by room\n       menus (see setState). */\n    fetchConstructorSuggestions() {\n      if (this.cnstrcSuggestionsPromise) return this.cnstrcSuggestionsPromise;\n      // Column switched off: no pod call, and the aside falls back to the\n      // merchant's Trending / Browse by room menus.\n      var pod = this.suggestionsEnabled ? this.pods.suggestions : '';\n      if (!pod) {\n        this.cnstrcSuggestionsPromise = Promise.resolve([]);\n        return this.cnstrcSuggestionsPromise;\n      }\n      var self = this;\n      this.cnstrcSuggestionsPromise = window.esrConstructor.load().then(function (client) {\n        if (!client) return [];\n        /* The section param is required, not optional: the pod lives in the Search\n           Suggestions section, and without naming it the request defaults to\n           Products and the pod is reported as not found (404). */\n        return client.recommendations\n          .getRecommendations(pod, {\n            numResults: 5,\n            section: 'Search Suggestions'\n          })\n          .then(function (res) {\n            var r = (res && res.response && res.response.results) || [];\n            /* Pod meta kept for the container attributes - the zero-state suggestion\n               list is a recommendations surface just like the product grid, so it\n               needs the pod id, result id and response total. Stashed rather than\n               returned so the resolved value stays a plain list of suggestions. */\n            self.cnstrcSuggestionsMeta = {\n              podId: pod,\n              resultId: res && res.result_id,\n              numResults: res && res.response && res.response.total_num_results\n            };\n            return r.map(function (item) {\n              return {\n                text: item.value,\n                url: self.searchUrl + '?q=' + encodeURIComponent(item.value),\n                // The pod's own id for the term, and the strategy that chose it.\n                id: (item.data && item.data.id) || '',\n                strategyId: (item.strategy && item.strategy.id) || ''\n              };\n            });\n          })\n          .catch(function () { return []; });\n      }).catch(function () { return []; });\n      return this.cnstrcSuggestionsPromise;\n    }\n\n    /* Maps the autocomplete `Categories` section onto the shape the renderer already\n       expects. Each entry carries only `value` (the display name) and `data.id`,\n       which IS the Shopify collection handle, so no Shopify lookup is needed.\n\n       The old group-tree walk and its roll-up deny-list are gone. TECH LEAD'S CALL,\n       11 Sept 2026: the deny-list existed to clean up a group tree we were never\n       meant to read - it was rooted at \"all\" and mixed \"All ...\" and \"Sale - ...\"\n       merchandising buckets in with real categories. Constructor curate this section\n       themselves, so there is nothing to filter and a deny-list here would only\n       second-guess their merchandising.\n\n       Also the TECH LEAD'S CALL: the column stays at FIVE even though the index\n       holds thirteen for a broad term, to keep the layout exactly as it is.\n\n       THE COUNT is `data.products_count`, which Constructor made displayable on\n       this section on 11 Sept 2026. It is the number of LIVE products in that\n       collection, NOT the number matching the search term: Dining Chairs reports\n       52, and that collection holds 80 products of which exactly 52 are active and\n       published (verified against the staging store). Alex knows and chose it.\n\n       It is absent on most stores and that is expected, not an error. As of\n       11 Sept 2026 the field is configured on the STAGING index only\n       (key_4wMDAVrByXOnS6Iy returns `data` keys id/products_count/url); AU and NZ\n       return `data` keys of id alone until Constructor apply the config there. So\n       `count` is null far more often than not, and the renderer must treat that as\n       the normal case - see the markup below.\n\n       Order is still Constructor's own relevance order. The count is NOT used for\n       sorting: the old count sort went with the group tree and does not come back.\n       TECH LEAD'S CALL, 11 Sept 2026: a zero is not rendered either. A category\n       with no live products should not be in the list at all, and \"0\" beside a\n       collection name reads as a fault rather than as information. */\n    constructorCategories(items) {\n      return (items || [])\n        .map(function (item) {\n          var data = (item && item.data) || {};\n          /* Only a number, or a non-empty numeric string, is considered - so a\n             boolean cannot become \"1\" via Number(true). Number() rather than\n             parseInt because it rejects \"52abc\" outright instead of silently\n             salvaging the \"52\". Then only a finite value above zero survives:\n             null, undefined, '', NaN, Infinity, negatives and 0 all render\n             nothing. */\n          var raw = data.products_count;\n          var count = null;\n          if (typeof raw === 'number' || (typeof raw === 'string' && raw !== '')) {\n            var n = Number(raw);\n            if (isFinite(n) && n > 0) count = Math.round(n);\n          }\n          return {\n            group_id: data.id || '',\n            display_name: (item && item.value) || '',\n            count: count\n          };\n        })\n        .filter(function (g) { return g.group_id && g.display_name; });\n    }\n\n    renderConstructorResults(query, items, suggestionItems, categories) {\n      var self = this;\n\n      /* Products are the theme's standard card, rendered by Liquid a request at a time,\n         so they land a beat after the aside and the categories. Two consequences worth\n         knowing:\n\n         - The previous term's cards are left in place until the new ones are ready,\n           rather than the grid emptying on every keystroke. `aria-busy` says so while\n           it is in flight.\n         - The token guard is the one fetchResultsFromConstructor uses: a fast typist\n           outruns a hydration, and a stale term's cards must never land in the grid. */\n      var token = this.cnstrcToken;\n      if (this.liveProducts) {\n        if (items.length) {\n          this.liveProducts.setAttribute('aria-busy', 'true');\n          window.esrConstructor.hydrateAll(items, { section: 'Products' }).then(function (rows) {\n            if (token !== self.cnstrcToken || !self.liveProducts) return;\n            self.liveProducts.innerHTML = '';\n            rows.forEach(function (row) { self.liveProducts.appendChild(row.el); });\n            self.liveProducts.removeAttribute('aria-busy');\n            window.esrConstructor.initInjectedCards();\n          });\n        } else {\n          this.liveProducts.innerHTML = '';\n          this.liveProducts.removeAttribute('aria-busy');\n        }\n      }\n      if (this.viewAll) this.viewAll.href = this.searchUrl + '?q=' + encodeURIComponent(query) + '&type=product';\n\n      /* Query suggestions come from the autocomplete response while the shopper is\n         typing; the popular-searches pod only backs the idle state. */\n      var suggestions = (suggestionItems || []).map(function (item) {\n        return {\n          text: item.value,\n          url: self.searchUrl + '?q=' + encodeURIComponent(item.value),\n          /* Constructor's own id for the term. Carried through so the <li> can\n             tag it (Constructor request, 2026-08-11) - the mapping previously\n             kept only the label and the id never reached the renderer. */\n          id: (item.data && item.data.id) || ''\n        };\n      });\n      /* Categories. Label, plus a product count when Constructor return one. The\n         Liquid path renders the same span from `collection.all_products_count`\n         (sections/predictive-search-results.liquid), so both paths share one set\n         of CSS rules and look identical. */\n      var cats = categories || [];\n      if (this.categoriesList) {\n        var esc = function (s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;'); };\n        var root = (window.Shopify && window.Shopify.routes && window.Shopify.routes.root) || '/';\n        var base = root.replace(/\\/$/, '') + '/collections/';\n        this.categoriesList.innerHTML = cats.map(function (g) {\n          return '<li data-cnstrc-item-section=\"Categories\" data-cnstrc-item-id=\"' + esc(g.group_id) + '\"' +\n            ' data-cnstrc-item-name=\"' + esc(g.display_name) + '\">' +\n            '<a class=\"predictive-search__result-link\" href=\"' + base + encodeURIComponent(g.group_id) + '\">' +\n            '<span class=\"predictive-search__result-label\">' + esc(g.display_name) + '</span>' +\n            /* Count only when the mapper resolved a real number. On a store where\n               Constructor have not configured products_count - AU and NZ today -\n               this contributes NOTHING: no span, no dash, no zero, no placeholder,\n               so the column reads as deliberate rather than broken. Same span and\n               class as the native Shopify path renders from\n               sections/predictive-search-results.liquid, so the styling is shared\n               and nothing new is needed. */\n            (g.count === null ? '' :\n              '<span class=\"predictive-search__result-count\">' + esc(g.count) + '</span>') +\n            '</a></li>';\n        }).join('');\n      }\n\n      this.hasProducts = items.length > 0;\n      this.hasSuggestions = suggestions.length > 0;\n      this.hasCollections = cats.length > 0;\n\n      if (this.hasProducts || this.hasSuggestions || this.hasCollections) {\n        this.setState('results');\n        /* AFTER setState, not before. renderSuggestions decides whether to tag an\n           item by reading data-cnstrc-autosuggest off the panel, and setState is\n           what un-parks that attribute. Rendering first meant the panel was still\n           in the previous state, so every suggestion went out untagged while\n           Categories - whose attributes are unconditional - looked fine. */\n        this.renderSuggestions(suggestions);\n      } else {\n        /* Nothing matched, so the aside goes back to popular searches - the query\n           suggestions it was holding are no use against a term with no results. */\n        this.setState('no-results');\n        this.restoreConstructorSuggestions();\n      }\n    }\n\n    fetchResults(query) {\n      if (this.cnstrcMode) {\n        this.abort();\n        this.fetchResultsFromConstructor(query);\n        return;\n      }\n      if (!('AbortController' in window) || typeof fetch !== 'function') return;\n      this.abort();\n      this.controller = new AbortController();\n      var signal = this.controller.signal;\n      var self = this;\n      var q = encodeURIComponent(query);\n\n      // Query suggestions come only from the JSON endpoint (the predictive_search\n      // Liquid object has no queries); Search and Discovery powers this list. With\n      // the suggestions column switched off there is nowhere to put them, so the\n      // request is skipped rather than made and discarded.\n      var queriesReq = Promise.resolve(null);\n      if (this.suggestionsEnabled) {\n        queriesReq = fetch(this.suggestUrl + '.json?q=' + q + '&resources[type]=query&resources[limit]=6', { signal: signal })\n          .then(function (r) { return r.ok ? r.json() : null; })\n          .catch(function () { return null; });\n      }\n\n      // Rich collections (with counts) + product cards render server-side via the\n      // Section Rendering API so the product-card snippet is reused verbatim.\n      var sectionReq = Promise.resolve('');\n      if (this.resultsSection) {\n        sectionReq = fetch(this.suggestUrl + '?q=' + q + '&section_id=' + encodeURIComponent(this.resultsSection) + '&resources[type]=product,collection&resources[limit]=10&resources[limit_scope]=each', { signal: signal })\n          .then(function (r) { return r.ok ? r.text() : ''; })\n          .catch(function () { return ''; });\n      }\n\n      Promise.all([queriesReq, sectionReq]).then(function (res) {\n        if (signal.aborted) return;\n        self.renderResults(query, res[0], res[1]);\n      });\n    }\n\n    renderResults(query, queriesJson, sectionHtml) {\n      var suggestions = [];\n      if (queriesJson && queriesJson.resources && queriesJson.resources.results) {\n        suggestions = queriesJson.resources.results.queries || [];\n      }\n      this.renderSuggestions(suggestions);\n\n      var collectionsHtml = '';\n      var productsHtml = '';\n      if (sectionHtml) {\n        var doc = new DOMParser().parseFromString(sectionHtml, 'text/html');\n        var col = doc.querySelector('[data-ps-collections-list]');\n        var prod = doc.querySelector('[data-ps-products-list]');\n        collectionsHtml = col ? col.innerHTML.trim() : '';\n        productsHtml = prod ? prod.innerHTML.trim() : '';\n      }\n      if (this.categoriesList) this.categoriesList.innerHTML = collectionsHtml;\n      if (this.liveProducts) this.liveProducts.innerHTML = productsHtml;\n\n      if (this.viewAll) {\n        this.viewAll.href = this.searchUrl + '?q=' + encodeURIComponent(query) + '&type=product';\n      }\n\n      // A live group with no items (common: S&D has no query suggestions yet) is\n      // hidden in the results state so no empty heading/tab shows.\n      this.hasSuggestions = suggestions.length > 0;\n      this.hasCollections = collectionsHtml.length > 0;\n      this.hasProducts = productsHtml.length > 0;\n\n      // Results whenever there's anything to show. When products are empty but\n      // the aside has suggestions/collections, we STAY in the results state and\n      // the main panel shows \"No products for X\" (not the full \"No results\").\n      this.setState((this.hasProducts || this.hasSuggestions || this.hasCollections) ? 'results' : 'no-results');\n    }\n\n    /* @param {boolean} [recommendation] - True when the list came from the\n       popular-searches pod (the zero state) rather than from autocomplete. */\n    renderSuggestions(list, recommendation) {\n      if (!this.suggestionsList) return;\n      /* The panel is the autosuggest container, and it is a DESCENDANT of this\n         element - this.closest never matched it, so query suggestions were going out\n         untagged entirely. Read it off the panel instead, and honour the parking: the\n         attribute is only present while autosuggest is the live surface. */\n      var tagged = !!this.panel && this.panel.hasAttribute('data-cnstrc-autosuggest');\n      var html = '';\n      list.forEach(function (item) {\n        // styled_text is trusted first-party HTML (bolds the matched term).\n        var text = item.styled_text || item.text || '';\n        var url = item.url || '#';\n        var name = (item.text || '').replace(/\"/g, '&quot;');\n        var attrs = '';\n        if (recommendation) {\n          /* Zero state: pod-served, so the full recommendation item contract. Section\n             is \"Search Suggestions\" rather than \"Products\" - it names the pod's own\n             section, which is what Constructor joins the event back to. No price or\n             variation id: a term is not a purchasable item and the row has no CTA. */\n          attrs = ' data-cnstrc-item=\"recommendation\" data-cnstrc-item-section=\"Search Suggestions\"' +\n            ' data-cnstrc-item-name=\"' + name + '\"';\n          if (item.id) attrs += ' data-cnstrc-item-id=\"' + String(item.id).replace(/\"/g, '&quot;') + '\"';\n          if (item.strategyId) attrs += ' data-cnstrc-strategy-id=\"' + String(item.strategyId).replace(/\"/g, '&quot;') + '\"';\n        } else if (tagged) {\n          /* Typing: these are autocomplete items. The name is the plain query text,\n             not the styled markup. The id is included when the response carries one\n             (Constructor request, 2026-08-11 - it was previously omitted on their\n             earlier guidance). Native Shopify suggestions have no id, so the\n             attribute is simply left off there rather than emitted empty. */\n          attrs = ' data-cnstrc-item-section=\"Search Suggestions\" data-cnstrc-item-name=\"' + name + '\"';\n          if (item.id) attrs += ' data-cnstrc-item-id=\"' + String(item.id).replace(/\"/g, '&quot;') + '\"';\n        }\n        html += '<li' + attrs + '><a class=\"predictive-search__result-link\" href=\"' + url + '\"><span class=\"predictive-search__result-label\">' + text + '</span></a></li>';\n      });\n      this.suggestionsList.innerHTML = html;\n    }\n\n    // idle: static aside + featured. results: live aside + product cards.\n    // no-results: static aside + message + category cards. data-state drives\n    // the mobile layout; the [hidden] toggles drive the desktop swaps.\n    /* Moves data-cnstrc-item-section to/from a parked attribute name so hidden\n       cards stop counting as autocomplete items without losing which section they\n       belong to. Reversible, and a no-op once already in the requested state. */\n    parkCnstrcSections(scope, park) {\n      var from = park ? 'data-cnstrc-item-section' : 'data-cnstrc-item-section-parked';\n      var to = park ? 'data-cnstrc-item-section-parked' : 'data-cnstrc-item-section';\n      var nodes = scope.querySelectorAll('[' + from + ']');\n      for (var i = 0; i < nodes.length; i++) {\n        nodes[i].setAttribute(to, nodes[i].getAttribute(from));\n        nodes[i].removeAttribute(from);\n      }\n    }\n\n    /* Same idea, for container attributes on a single element: rename them out of the\n       way and back rather than rebuilding the panel.\n\n       Constructor's container types must not nest. The zero state is a recommendations\n       container that lives inside the panel, which is the autosuggest container, so\n       whichever one is not the current surface has to be parked or an item resolves to\n       two containers at once. Parking survives a swap in both directions because the\n       value is carried across, so a parked result id is still there when the shopper\n       clears the field and returns to the zero state. */\n    parkCnstrcAttrs(el, park, names) {\n      if (!el || !names) return;\n      names.forEach(function (name) {\n        var from = park ? name : name + '-parked';\n        var to = park ? name + '-parked' : name;\n        if (!el.hasAttribute(from)) return;\n        el.setAttribute(to, el.getAttribute(from));\n        el.removeAttribute(from);\n      });\n    }\n\n    setState(state) {\n      this.setAttribute('data-state', state);\n      var isIdle = state === 'idle';\n      var isResults = state === 'results';\n      var isNoResults = state === 'no-results';\n      var query = this.currentQuery();\n\n      // In the results state, the main panel shows product cards when there are\n      // any, otherwise the \"No products for X\" message (the aside still shows\n      // its live suggestions/collections).\n      var showProducts = isResults && this.hasProducts;\n      var showNoProducts = isResults && !this.hasProducts;\n\n      if (this.idleTitle) this.idleTitle.hidden = !isIdle;\n      if (this.products) this.products.hidden = !isIdle;\n\n      /* Constructor: a card is only an autocomplete item while its container is the\n         one on screen. Both product containers stay in the DOM across states, so the\n         hidden one has its section attribute parked - otherwise the beacon reports\n         the idle featured products alongside the live results and double counts. */\n      if (this.products) this.parkCnstrcSections(this.products, !isIdle);\n      if (this.liveProducts) this.parkCnstrcSections(this.liveProducts, !showProducts);\n\n      /* Swap which Constructor container is live, in place - the shopper typing must\n         not cost a rebuild of the panel. Exactly one type is live at a time, because\n         the recommendations containers sit INSIDE the autosuggest one and nesting them\n         makes an item's surface ambiguous.\n\n         Autosuggest is live only in the results state. Idle is the zero state, and\n         no-results is not an autosuggest surface either: its product grid is hidden,\n         its category list is cleared, and its aside is back on the popular-searches\n         pod, so nothing in the panel is an autocomplete item.\n\n         Two recommendations containers, with different lifetimes: the product grid is\n         idle-only (it is hidden outside idle), while the suggestion list holds pod\n         terms in both idle and no-results. */\n      if (this.cnstrcMode) {\n        this.parkCnstrcAttrs(this.panel, !isResults, ['data-cnstrc-autosuggest']);\n        this.parkCnstrcAttrs(this.products, !isIdle, window.esrConstructor.recommendationAttrs);\n        this.parkCnstrcAttrs(this.suggestionsList, isResults, window.esrConstructor.recommendationAttrs);\n      }\n      // The heading wrapper only holds the idle title + the no-results/no-products\n      // message; when products are showing it is empty, so collapse it (otherwise\n      // the main panel's gap adds phantom space above \"Product results\").\n      if (this.heading) this.heading.hidden = showProducts;\n      if (this.resultsBar) this.resultsBar.hidden = !showProducts;\n      if (this.liveProducts) this.liveProducts.hidden = !showProducts;\n      // The message block covers both \"no products\" (partial) and full \"no results\".\n      if (this.noResults) this.noResults.hidden = !(isNoResults || showNoProducts);\n      // Merchant category cards are the fallback for both the \"no products\"\n      // (partial) and the full \"no results\" states.\n      if (this.categories) this.categories.hidden = !(isNoResults || showNoProducts);\n\n      // Aside: static content (Trending / Browse by Room + tab labels) shows in\n      // idle + no-results; live content (Suggestions / Categories) in results.\n      this.staticEls.forEach(function (el) { el.hidden = isResults; });\n      this.liveEls.forEach(function (el) { el.hidden = !isResults; });\n\n\n      // In the results state, collapse a live group (+ its mobile tab) when it\n      // has no items; the aside divider only shows when both live groups do.\n      var hideSuggestions = isResults && !this.hasSuggestions;\n      var hideCollections = isResults && !this.hasCollections;\n      if (this.suggestionsGroup) this.suggestionsGroup.hidden = hideSuggestions;\n      if (this.categoriesGroup) this.categoriesGroup.hidden = hideCollections;\n      if (this.suggestionsTab) this.suggestionsTab.hidden = hideSuggestions;\n      if (this.categoriesTab) this.categoriesTab.hidden = hideCollections;\n      if (this.asideDivider) this.asideDivider.hidden = hideSuggestions || hideCollections;\n\n      /* Constructor mode, ONE rule for every state: the engine takes the aside when it\n         has something to put there, and otherwise the merchant's Trending and Browse by\n         room menus show with their own headings. The aside itself is always visible.\n\n         With engine content: Suggestions is the popular-searches pod in idle, and the\n         query suggestions from autocomplete in the results state. Categories only exist\n         against a query, so that column shows in the results state only. Suggestions is\n         the floor between the two, so a live aside is never a blank panel.\n\n         Both branches set the static/live split EXPLICITLY rather than deferring to the\n         Shopify-path rules above. Those hide static content whenever there is a query\n         (hidden = isResults), which is right for the Shopify path - its live lists have\n         content - but under Constructor it produced a completely empty aside on any query\n         the engine answered with neither categories nor suggestions. Verified against the\n         index: \"l\" returns one group, \"li\" returns zero, and \"li\" was the blank one.\n\n         hasSuggestions and hasCollections are both false until a response arrives, so the\n         static menus also fill the in-flight window rather than an empty column - the\n         trap that seeding hasSuggestions true originally caused.\n\n         Runs last so it overrides the Shopify-path rules above. */\n      if (this.cnstrcMode) {\n        /* \"Has engine content\" means content AND a column to render it in. Each live\n           column lives inside its merchant menu's if-block in the Liquid, so a merchant who\n           set no Browse by room menu has no Categories column at all - and counting the\n           engine's groups as content when there is nowhere to put them blanked the aside\n           just as surely as the bug above. */\n        var liveSuggestions = !!this.hasSuggestions && !!this.suggestionsGroup;\n        var liveCategories = isResults && !!this.hasCollections && !!this.categoriesGroup;\n        var engineAside = liveSuggestions || liveCategories;\n\n        this.staticEls.forEach(function (el) { el.hidden = engineAside; });\n        this.liveEls.forEach(function (el) { el.hidden = !engineAside; });\n\n        var showSuggestions;\n        var showCategories;\n        if (engineAside) {\n          showCategories = liveCategories;\n          // Suggestions is the floor between the two columns.\n          showSuggestions = liveSuggestions || !liveCategories;\n        } else {\n          /* Merchant menus: show every column the merchant actually configured, the way\n             the Shopify path shows them in idle. A null group means its menu is unset,\n             so there was nothing to show in that column anyway. */\n          showSuggestions = !!this.suggestionsGroup;\n          showCategories = !!this.categoriesGroup;\n        }\n\n        if (this.suggestionsGroup) this.suggestionsGroup.hidden = !showSuggestions;\n        if (this.categoriesGroup) this.categoriesGroup.hidden = !showCategories;\n        if (this.suggestionsTab) this.suggestionsTab.hidden = !showSuggestions;\n        if (this.categoriesTab) this.categoriesTab.hidden = !showCategories;\n        if (this.asideDivider) this.asideDivider.hidden = !(showSuggestions && showCategories);\n        if (this.aside) this.aside.hidden = false;\n      }\n\n      // If the active mobile tab was just hidden, fall back to the other one.\n      if (isResults) this.ensureVisibleTab();\n\n      if (this.noResultsTitle) {\n        if (showNoProducts) {\n          this.noResultsTitle.textContent = this.noProductsLabel.replace('[query]', query);\n        } else if (isNoResults) {\n          this.noResultsTitle.textContent = this.noResultsLabel.replace('[query]', query);\n        }\n      }\n      // Announce result changes to screen readers.\n      if (this.status) {\n        if (showNoProducts) {\n          this.status.textContent = this.noProductsLabel.replace('[query]', query);\n        } else if (isNoResults) {\n          this.status.textContent = this.noResultsLabel.replace('[query]', query);\n        } else if (isResults) {\n          this.status.textContent = query;\n        } else {\n          this.status.textContent = '';\n        }\n      }\n      this.syncVideo();\n    }\n\n    // Category videos only play when the cards are actually on screen: drawer\n    // open, the category cards not hidden, and desktop (the cards are\n    // display:none on mobile). Otherwise pause them so nothing plays behind a\n    // hidden panel.\n    syncVideo() {\n      if (!this.categoryVideos.length) return;\n      var visible = this.isOpen && this.mql.matches && !!this.categories && !this.categories.hidden;\n      this.categoryVideos.forEach(function (video) {\n        if (visible) {\n          var played = video.play();\n          if (played && played.catch) played.catch(function () {});\n        } else {\n          video.pause();\n        }\n      });\n    }\n\n    // The close button stays available the whole time the overlay is open, so a\n    // single click always closes it (and clears the field) regardless of input.\n    // The field's own Clear button handles clearing without closing.\n    syncControls() {\n      this.closeButtons.forEach(function (btn) {\n        btn.hidden = true;\n      });\n      var btn = this.activeCloseBtn;\n      if (!btn) return;\n      btn.hidden = !this.isOpen;\n    }\n  }\n\n  if (!customElements.get('predictive-search')) {\n    customElements.define('predictive-search', PredictiveSearch);\n  }\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"price\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    function closeAll() {\n      document.querySelectorAll('.price__promo-info.is-open').forEach(function (info) {\n        info.classList.remove('is-open');\n        var t = info.querySelector('.price__promo-toggle');\n        if (t) t.setAttribute('aria-expanded', 'false');\n      });\n    }\n\n    document.addEventListener('click', function (e) {\n      var toggle = e.target.closest('.price__promo-toggle');\n      if (toggle) {\n        var info = toggle.closest('.price__promo-info');\n        var isOpen = info.classList.toggle('is-open');\n        toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');\n        return;\n      }\n      // A click inside the tooltip (e.g. the link) leaves it open; anywhere\n      // else on the page closes any open tooltip.\n      if (e.target.closest('.price__promo-info')) return;\n      closeAll();\n    });\n\n    document.addEventListener('keydown', function (e) {\n      if (e.key === 'Escape') closeAll();\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"product-card\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.__esProductCardQuickAdd) return;\n    window.__esProductCardQuickAdd = true;\n\n    // --- Image carousel (seamless loop via cloned first/last slides) ---\n    // Track layout once set up: [clone(last), real0 .. real(n-1), clone(first)].\n    // Position 0 = leading clone, 1..n = real slides, n+1 = trailing clone.\n    // A wrap is a single step onto a clone, then an invisible snap to the\n    // matching real slide on transitionend.\n    function carouselReal(track) {\n      return track.querySelectorAll('.product-card__slide:not(.product-card__slide--clone)');\n    }\n\n    // Set the track position; when instant, the transform transition is briefly\n    // disabled so the move is not animated (used for setup, snaps and resets).\n    function carouselSet(track, pos, instant) {\n      if (instant) {\n        track.style.transition = 'none';\n      }\n      track.style.setProperty('--carousel-index', String(pos));\n      track.dataset.pos = String(pos);\n      if (instant) {\n        void track.offsetWidth;\n        track.style.transition = '';\n      }\n    }\n\n    // Clone the first/last real slides and park on the first real slide.\n    function carouselSetup(track) {\n      var clones = track.querySelectorAll('.product-card__slide--clone');\n      for (var i = 0; i < clones.length; i++) clones[i].remove();\n\n      var slides = carouselReal(track);\n      var count = slides.length;\n      track.dataset.count = String(count);\n      if (count <= 1) {\n        carouselSet(track, 0, true);\n        return count;\n      }\n      var firstClone = slides[0].cloneNode(true);\n      var lastClone = slides[count - 1].cloneNode(true);\n      firstClone.classList.add('product-card__slide--clone');\n      lastClone.classList.add('product-card__slide--clone');\n      track.insertBefore(lastClone, slides[0]);\n      track.appendChild(firstClone);\n      carouselSet(track, 1, true);\n      return count;\n    }\n\n    // The pristine (no-clone) slide markup, used to cache/restore on swatch swap.\n    function carouselPristine(track) {\n      var slides = carouselReal(track);\n      var html = '';\n      for (var i = 0; i < slides.length; i++) html += slides[i].outerHTML;\n      return html;\n    }\n\n    /* #1110: Shopify answers a refused add with 422 and a body that names the\n       product. Reading response.json() without checking response.ok made that\n       indistinguishable from success - cart:updated fired, the drawer found\n       nothing new, and the shopper was told nothing. */\n    function qaMessage(body) {\n      if (body && typeof body === 'object') {\n        if (body.description) return String(body.description);\n        if (body.message) return String(body.message);\n      }\n      return '';\n    }\n    var QA_FALLBACK = 'Sorry, this could not be added to your cart. Please try again.';\n    function qaShowError(form, text) {\n      var box = form.querySelector('[data-cart-add-error]');\n      if (!box) return;\n      box.textContent = text || '';\n      box.hidden = !text;\n    }\n\n    document.addEventListener('submit', function (event) {\n      var form = event.target.closest('[data-quick-add]');\n      if (!form) return;\n      event.preventDefault();\n\n      // The form holds both the desktop full-width button and the mobile icon\n      // button; mark both busy so whichever is visible reflects the state.\n      var buttons = form.querySelectorAll('button');\n      for (var bi = 0; bi < buttons.length; bi++) {\n        buttons[bi].setAttribute('aria-busy', 'true');\n        buttons[bi].disabled = true;\n      }\n\n      qaShowError(form, '');\n\n      fetch(form.action, {\n        method: 'POST',\n        headers: { Accept: 'application/json' },\n        body: new FormData(form)\n      })\n        .then(function (response) {\n          return response.json().then(function (body) {\n            return { ok: response.ok, body: body };\n          });\n        })\n        .then(function (res) {\n          if (!res.ok) {\n            qaShowError(form, qaMessage(res.body) || QA_FALLBACK);\n            return;\n          }\n          document.dispatchEvent(\n            new CustomEvent('cart:updated', { bubbles: true, detail: { item: res.body } })\n          );\n        })\n        .catch(function () { qaShowError(form, QA_FALLBACK); })\n        .finally(function () {\n          for (var bj = 0; bj < buttons.length; bj++) {\n            buttons[bj].removeAttribute('aria-busy');\n            buttons[bj].disabled = false;\n          }\n        });\n    });\n\n    document.addEventListener('click', function (event) {\n      var swatch = event.target.closest('[data-swatch-image]');\n      if (!swatch) return;\n\n      var image = swatch.getAttribute('data-swatch-image');\n      if (!image) return;\n\n      var card = swatch.closest('.product-card');\n      if (!card) return;\n\n      event.preventDefault();\n\n      var srcset = swatch.getAttribute('data-swatch-srcset');\n\n      // Keep the styled (lifestyle) image in sync with the chosen colour. The\n      // collection \"Styled\" toggle (applyStyled in collection.liquid) reads the\n      // card root's data-styled-image, so mirror this colour's styled image onto\n      // it - otherwise the toggle would show the card's original colour.\n      var styledImage = swatch.getAttribute('data-swatch-styled-image');\n      var styledSrcset = swatch.getAttribute('data-swatch-styled-srcset');\n      if (styledImage) {\n        card.setAttribute('data-styled-image', styledImage);\n        if (styledSrcset) {\n          card.setAttribute('data-styled-srcset', styledSrcset);\n        } else {\n          card.removeAttribute('data-styled-srcset');\n        }\n      } else {\n        card.removeAttribute('data-styled-image');\n        card.removeAttribute('data-styled-srcset');\n      }\n\n      // Is the grid currently showing styled imagery? (data-styled=\"true\" lives\n      // on the collection custom element wrapping the cards.)\n      var styledOn = !!card.closest('[data-styled=\"true\"]') && !!styledImage;\n\n      var primary = card.querySelector('.product-card__image--primary');\n      if (primary) {\n        // Refresh the cached \"standard\" image so toggling Styled off restores\n        // the selected colour, not the original.\n        primary.dataset.standardSrc = image;\n        primary.dataset.standardSrcset = srcset || '';\n        if (styledOn) {\n          primary.src = styledImage;\n          if (styledSrcset) {\n            primary.srcset = styledSrcset;\n          } else {\n            primary.removeAttribute('srcset');\n          }\n        } else {\n          primary.src = image;\n          if (srcset) {\n            primary.srcset = srcset;\n          } else {\n            primary.removeAttribute('srcset');\n          }\n        }\n      }\n\n      // Carousel -> the selected product's images (hover image first). The\n      // track HTML is swapped below from the swatch fragment; here we just keep\n      // a reference and reset to the first slide.\n\n      var selected = card.querySelector('.product-card__swatch--selected');\n      if (selected) {\n        selected.classList.remove('product-card__swatch--selected');\n      }\n      swatch.classList.add('product-card__swatch--selected');\n\n      var link = card.querySelector('.product-card__link');\n      var url = swatch.getAttribute('href');\n      if (link) {\n        if (url) {\n          link.setAttribute('href', url);\n        }\n        var title = swatch.getAttribute('data-product-title');\n        if (title) {\n          link.textContent = title;\n        }\n      }\n\n      // Re-bind theWishlist heart to the selected colour product so adding to\n      // wishlist targets the shown product. The matching ProductJson-{id} /\n      // OptionJson-{id} blocks are emitted per visible swatch above.\n      var wishlist = card.querySelector('.btn-wishlist');\n      var productId = swatch.getAttribute('data-product-id');\n      if (wishlist && productId) {\n        wishlist.className = wishlist.className.replace(/\\bbutton-\\d+\\b/, 'button-' + productId);\n        wishlist.setAttribute('data-product-id', productId);\n        wishlist.setAttribute('data-product-title', swatch.getAttribute('data-product-title') || '');\n        wishlist.setAttribute('data-has-only-variant', swatch.getAttribute('data-has-only-variant') || 'true');\n\n        // Rewriting the attributes alone is not enough: the app captures the\n        // product id in its click listener's closure at bind time, so the heart\n        // would keep adding the ORIGINAL colour (task #19044869). Fire the\n        // app's own re-bind hook, scoped to this card - it re-reads the updated\n        // attributes and re-binds a fresh clone of the button. Harmless when\n        // the app hasn't initialised yet (no listener; its later init reads the\n        // updated attributes anyway).\n        document.body.dispatchEvent(new CustomEvent('wishlist:refresh', {\n          detail: { scope: { container: card } }\n        }));\n\n        // The re-bind REPLACED the button node (the app clones it to drop the\n        // stale listener), so re-query it, then sync the filled-heart state to\n        // the selected product - the .is-wishlisted class otherwise carries\n        // over from the previous colour. Same check as twc-scripts.liquid.\n        wishlist = card.querySelector('.btn-wishlist');\n        if (wishlist && typeof theWishlist !== 'undefined' && typeof theWishlist.checkVariantInWishlist === 'function') {\n          var wishlisted = false;\n          var productJson = document.getElementById('ProductJson-' + productId);\n          if (productJson) {\n            try {\n              var wlVariants = (JSON.parse(productJson.textContent) || {}).variants || [];\n              for (var wv = 0; wv < wlVariants.length; wv++) {\n                if (theWishlist.checkVariantInWishlist(wlVariants[wv].id)) {\n                  wishlisted = true;\n                  break;\n                }\n              }\n            } catch (wlErr) {}\n          }\n          wishlist.classList.toggle('is-wishlisted', wishlisted);\n        }\n      }\n\n      // Point quick-add at the selected colour product.\n      var variantId = swatch.getAttribute('data-variant-id');\n      var quickAddForm = card.querySelector('[data-quick-add] input[name=\"id\"]');\n      if (quickAddForm && variantId) {\n        quickAddForm.value = variantId;\n      }\n      var moreOptions = card.querySelectorAll('.product-card__quick-add a[href]');\n      for (var moi = 0; moi < moreOptions.length; moi++) {\n        if (url) moreOptions[moi].setAttribute('href', url);\n      }\n\n      // Keep Constructor's item attributes on the selected colour. A swatch swaps the\n      // card to a different PRODUCT, so the item id, the variation and the price all\n      // move together. Absent when Constructor is off, in which case there is nothing\n      // to update.\n      //\n      // The id is the sibling's variant SKU, matching what `constructor-item-attrs`\n      // renders and what the feed is keyed on - BOTH item id and variation id are the\n      // SKU there. This used to write the handle and the Shopify variant id, from when\n      // the index was keyed on handle: after the re-key, a click on a swapped card\n      // reported an item id that joined to nothing.\n      var cnstrcHandle = swatch.getAttribute('data-cnstrc-handle');\n      var cnstrcSku = swatch.getAttribute('data-cnstrc-sku');\n      if (cnstrcHandle && card.hasAttribute('data-cnstrc-item-id')) {\n        var cnstrcId = cnstrcSku || cnstrcHandle;\n        card.setAttribute('data-cnstrc-item-id', cnstrcId);\n        var cnstrcTitle = swatch.getAttribute('data-product-title');\n        if (cnstrcTitle) card.setAttribute('data-cnstrc-item-name', cnstrcTitle);\n        card.setAttribute('data-cnstrc-item-variation-id', cnstrcId);\n        var cnstrcPrice = swatch.getAttribute('data-cnstrc-price');\n        if (cnstrcPrice) card.setAttribute('data-cnstrc-item-price', cnstrcPrice);\n      }\n\n      // Swap badge, price and rating to the selected colour. Siblings carry a\n      // server-rendered <template> fragment; the current swatch has none, so we\n      // cache the card's original (already-rendered) badge/price/rating once and\n      // restore from that - avoids duplicating the current product's fragment.\n      var badgeNode = card.querySelector('.product-card__badge');\n      var priceNode = card.querySelector('.price');\n      var metaNode = card.querySelector('.product-card__meta');\n      var ratingNode = metaNode ? metaNode.querySelector('.rating') : null;\n      var trackNode = card.querySelector('.product-card__carousel-track');\n\n      if (!card.__esOriginalFragments) {\n        card.__esOriginalFragments = {\n          badge: badgeNode ? badgeNode.innerHTML : '',\n          price: priceNode ? priceNode.outerHTML : null,\n          rating: ratingNode ? ratingNode.outerHTML : '',\n          carousel: trackNode ? carouselPristine(trackNode) : null\n        };\n      }\n\n      var li = swatch.closest('li');\n      var fragments = li ? li.querySelector('template[data-swatch-fragments]') : null;\n      var badgeHTML, priceHTML, ratingHTML, carouselHTML;\n      if (fragments) {\n        var content = fragments.content;\n        var bf = content.querySelector('[data-fragment=\"badge\"]');\n        var pf = content.querySelector('[data-fragment=\"price\"]');\n        var rf = content.querySelector('[data-fragment=\"rating\"]');\n        var cf = content.querySelector('[data-fragment=\"carousel\"]');\n        badgeHTML = bf ? bf.innerHTML : '';\n        priceHTML = pf ? pf.innerHTML : null;\n        ratingHTML = rf ? rf.innerHTML.trim() : '';\n        carouselHTML = cf ? cf.innerHTML : null;\n      } else {\n        badgeHTML = card.__esOriginalFragments.badge;\n        priceHTML = card.__esOriginalFragments.price;\n        ratingHTML = card.__esOriginalFragments.rating;\n        carouselHTML = card.__esOriginalFragments.carousel;\n      }\n\n      // Rebuild the carousel from the selected product's slides, clear the loop\n      // setup (clones/position re-init lazily on the next arrow click), reset to\n      // the first slide (its hover image), and show arrows only if >1 slide.\n      if (trackNode && carouselHTML != null) {\n        trackNode.innerHTML = carouselHTML;\n        carouselSet(trackNode, 0, true);\n        trackNode.scrollLeft = 0;\n        delete trackNode.dataset.pos;\n        delete trackNode.dataset.count;\n        var navNode = card.querySelector('.product-card__nav');\n        if (navNode) {\n          navNode.hidden = trackNode.querySelectorAll('.product-card__slide').length <= 1;\n        }\n      }\n\n      if (badgeNode) {\n        badgeNode.innerHTML = badgeHTML;\n      }\n      if (priceNode && priceHTML != null) {\n        priceNode.outerHTML = priceHTML;\n      }\n      if (metaNode) {\n        if (ratingNode) {\n          if (ratingHTML) {\n            ratingNode.outerHTML = ratingHTML;\n          } else {\n            ratingNode.remove();\n          }\n        } else if (ratingHTML) {\n          metaNode.insertAdjacentHTML('beforeend', ratingHTML);\n        }\n      }\n\n      // Same focus release as the arrows: a mouse click leaves the swatch link\n      // focused, so :focus-within would keep the hover overlay visible after\n      // the pointer leaves. Keep focus for keyboard activation (detail 0).\n      if (event.detail !== 0) {\n        swatch.blur();\n      }\n    });\n\n    // Carousel arrows: step one slide; clones make the wrap seamless.\n    document.addEventListener('click', function (event) {\n      var arrow = event.target.closest('[data-carousel-prev], [data-carousel-next]');\n      if (!arrow) return;\n      event.preventDefault();\n\n      var media = arrow.closest('.product-card__media');\n      var track = media ? media.querySelector('.product-card__carousel-track') : null;\n      if (!track) return;\n\n      // Lazily clone the slides the first time this carousel is used (and after\n      // a swatch swap, which clears the setup so it re-runs here).\n      var count;\n      if (track.dataset.pos === undefined || track.dataset.count === undefined) {\n        count = carouselSetup(track);\n      } else {\n        count = parseInt(track.dataset.count, 10);\n      }\n      if (count <= 1) return;\n\n      var step = arrow.hasAttribute('data-carousel-next') ? 1 : -1;\n      var pos = parseInt(track.dataset.pos, 10);\n\n      // If we're parked on a clone (a wrap whose transitionend snap hasn't run\n      // yet - e.g. rapid clicks interrupt the transition), jump instantly to its\n      // real twin before stepping. This keeps pos within [0, count + 1] no\n      // matter how fast the arrows are clicked, so the track never scrolls off\n      // into blank space.\n      if (pos >= count + 1) {\n        carouselSet(track, 1, true);\n        pos = 1;\n      } else if (pos <= 0) {\n        carouselSet(track, count, true);\n        pos = count;\n      }\n\n      carouselSet(track, pos + step, false);\n\n      // A mouse click leaves the arrow focused, so :focus-within would keep the\n      // overlay (carousel + arrows) visible after the pointer leaves. Drop focus\n      // for pointer-driven clicks (event.detail > 0) but keep it for keyboard\n      // activation (detail 0) so tab users still see the arrows.\n      if (event.detail !== 0) {\n        arrow.blur();\n      }\n    });\n\n    document.addEventListener('transitionend', function (event) {\n      var target = event.target;\n      if (!target.classList) return;\n\n      // Overlay finished fading out -> reset to the first real slide, invisibly.\n      // Resetting on mouseleave instead animated the slides back while the\n      // overlay was still visible, which looked wrong.\n      if (target.classList.contains('product-card__carousel') && event.propertyName === 'opacity') {\n        if (getComputedStyle(target).opacity !== '0') return;\n        var t = target.querySelector('.product-card__carousel-track');\n        if (!t) return;\n        var c = parseInt(t.dataset.count, 10);\n        if (!isNaN(c)) carouselSet(t, c > 1 ? 1 : 0, true);\n        return;\n      }\n\n      // Track finished a move onto a clone -> snap to the matching real slide so\n      // the loop is seamless (no full-width scroll back).\n      if (target.classList.contains('product-card__carousel-track') && event.propertyName === 'transform') {\n        var count = parseInt(target.dataset.count, 10);\n        var pos = parseInt(target.dataset.pos, 10);\n        if (isNaN(count) || isNaN(pos)) return;\n        if (pos === count + 1) {\n          carouselSet(target, 1, true);\n        } else if (pos === 0) {\n          carouselSet(target, count, true);\n        }\n      }\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"product-discontinued\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (customElements.get('discontinued-notice')) return;\n\n    class DiscontinuedNotice extends HTMLElement {\n      connectedCallback() {\n        if (this.__init) return;\n        this.__init = true;\n        this.trigger = this.querySelector('[data-discontinued-scroll]');\n        this.onClick = this.onClick.bind(this);\n        if (this.trigger) this.trigger.addEventListener('click', this.onClick);\n      }\n\n      onClick() {\n        var target = document.querySelector('.featured-products-section');\n        if (!target) return;\n        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n        target.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'start' });\n      }\n\n      disconnectedCallback() {\n        if (this.trigger) this.trigger.removeEventListener('click', this.onClick);\n      }\n    }\n\n    customElements.define('discontinued-notice', DiscontinuedNotice);\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"quantity\"] && !Shopify.designMode) return;\n  try {\n    // Delegated (not per-element) so steppers rendered after page load - e.g. cart\n  // line items re-rendered via the Section Rendering API - work without re-binding.\n  // Per-element binding only covered the markup present on load, so a re-rendered\n  // stepper's buttons dispatched no change event and quantity-0 removal silently\n  // failed for those lines.\n  function esQuantitySync(root) {\n    var input = root.querySelector('[data-quantity-input]');\n    if (!input) return;\n    var dec = root.querySelector('[data-quantity-decrease]');\n    var inc = root.querySelector('[data-quantity-increase]');\n    var min = input.min !== '' ? parseInt(input.min, 10) : null;\n    var max = input.max !== '' ? parseInt(input.max, 10) : null;\n    var val = parseInt(input.value, 10);\n    if (isNaN(val)) val = min !== null ? min : 0;\n    if (min !== null && val < min) val = min;\n    if (max !== null && val > max) val = max;\n    input.value = val;\n    if (dec && min !== null) dec.disabled = val <= min;\n    if (inc && max !== null) inc.disabled = val >= max;\n  }\n\n  document.addEventListener('click', function (e) {\n    var btn = e.target.closest('[data-quantity-decrease], [data-quantity-increase]');\n    if (!btn || btn.disabled) return;\n    var root = btn.closest('[data-quantity]');\n    if (!root) return;\n    var input = root.querySelector('[data-quantity-input]');\n    if (!input || input.disabled) return;\n    var delta = btn.hasAttribute('data-quantity-increase') ? 1 : -1;\n    input.value = (parseInt(input.value, 10) || 0) + delta;\n    esQuantitySync(root);\n    input.dispatchEvent(new Event('change', { bubbles: true }));\n  });\n\n  document.addEventListener('change', function (e) {\n    var input = e.target.closest('[data-quantity-input]');\n    if (!input) return;\n    var root = input.closest('[data-quantity]');\n    if (root) esQuantitySync(root);\n  });\n\n  // Initial pass to clamp values and set button disabled states on load.\n  document.querySelectorAll('[data-quantity]').forEach(esQuantitySync);\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"search-input\"] && !Shopify.designMode) return;\n  try {\n    document.querySelectorAll('[data-search]').forEach(function (root) {\n    var field = root.querySelector('[data-search-field]');\n    var clear = root.querySelector('[data-search-clear]');\n    if (!field || !clear) return;\n    function sync() { clear.hidden = field.value.length === 0; }\n    field.addEventListener('input', sync);\n    clear.addEventListener('click', function () {\n      field.value = '';\n      sync();\n      field.focus();\n    });\n    sync();\n  });\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"shopify-facets\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    if (window.esrShopifyFacets) return;\n    window.esrShopifyFacets = true;\n\n    /* Params carried over from the current URL when they are not already in the\n       form: the search query and result type, and the grid display preferences.\n       Deliberately NOT `loaded`/`page` - a changed filter set restarts paging. */\n    var PRESERVE = ['q', 'type', 'view', 'cols', 'styled'];\n\n    /* Monotonic request id: a slow response must not clobber a newer one. */\n    var seq = 0;\n\n    function getForm() {\n      return document.querySelector('[data-shopify-filters]');\n    }\n\n    function currentGrid() {\n      return document.querySelector('[data-collection-grid], [data-sf-grid]');\n    }\n\n    /* ---------- URL ---------- */\n\n    function buildUrl(form) {\n      var url = new URL(form.getAttribute('action') || window.location.pathname, window.location.origin);\n      var data = new FormData(form);\n      data.forEach(function (value, key) {\n        if (value === '' || value == null) return;\n        /* The price Min/Max text fields are display-only mirrors; the submitted\n           price lives on the hidden gte/lte inputs. */\n        if (key.indexOf('-display') !== -1) return;\n        url.searchParams.append(key, value);\n      });\n      var current = new URL(window.location.href).searchParams;\n      PRESERVE.forEach(function (key) {\n        if (!url.searchParams.has(key) && current.has(key)) {\n          url.searchParams.set(key, current.get(key));\n        }\n      });\n      return url;\n    }\n\n    /* ---------- Swap ---------- */\n\n    /* Groups the shopper has opened, so a re-render does not collapse the\n       drawer under them (the accordion state lives in aria-expanded + an\n       inline panel height). */\n    function openGroups() {\n      var open = {};\n      document.querySelectorAll('[data-facet-group]').forEach(function (group) {\n        var summary = group.querySelector('.collection-filters__group-summary');\n        if (summary && summary.getAttribute('aria-expanded') === 'true') {\n          open[group.getAttribute('data-facet-group')] = true;\n        }\n      });\n      return open;\n    }\n\n    function restoreGroups(open) {\n      Object.keys(open).forEach(function (name) {\n        var group = document.querySelector('[data-facet-group=\"' + CSS.escape(name) + '\"]');\n        if (!group) return;\n        var summary = group.querySelector('.collection-filters__group-summary');\n        var panel = group.querySelector('.collection-filters__group-panel');\n        if (summary) summary.setAttribute('aria-expanded', 'true');\n        if (panel) panel.style.height = 'auto';\n      });\n    }\n\n    /* Replaces every data-sf-swap node with its counterpart from the fetched\n       section, paired by key in document order. */\n    function swapAll(doc) {\n      var pairs = {};\n      document.querySelectorAll('[data-sf-swap]').forEach(function (node) {\n        var key = node.getAttribute('data-sf-swap');\n        pairs[key] = pairs[key] || { current: [], incoming: [] };\n        pairs[key].current.push(node);\n      });\n      doc.querySelectorAll('[data-sf-swap]').forEach(function (node) {\n        var key = node.getAttribute('data-sf-swap');\n        pairs[key] = pairs[key] || { current: [], incoming: [] };\n        pairs[key].incoming.push(node);\n      });\n      Object.keys(pairs).forEach(function (key) {\n        pairs[key].current.forEach(function (node, i) {\n          var replacement = pairs[key].incoming[i];\n          if (replacement) node.replaceWith(document.importNode(replacement, true));\n        });\n      });\n    }\n\n    function afterSwap(doc) {\n      /* The swapped price control is fresh markup; the theme's range module\n         binds on load only, guards per root, and queries the document - so this\n         is both necessary and safe on every swap. */\n      if (window.esCollectionPriceRange) window.esCollectionPriceRange.init();\n\n      /* The collection page's <collection-grid> element caches references and\n         counts at connect; re-point them at the swapped nodes so Load more and\n         the showing line keep working against the filtered set. */\n      var host = document.querySelector('collection-grid');\n      if (host) {\n        host.grid = host.querySelector('[data-collection-grid]');\n        var incomingHost = doc.querySelector('collection-grid');\n        var total = incomingHost && incomingHost.getAttribute('data-total');\n        if (total != null) {\n          host.setAttribute('data-total', total);\n          host.total = parseInt(total, 10) || 0;\n        }\n        host.loadedPages = 1;\n        if (typeof host.applyStyled === 'function') host.applyStyled();\n      }\n    }\n\n    function refresh(url, writeHistory) {\n      var form = getForm();\n      if (!form) {\n        window.location.href = url.toString();\n        return;\n      }\n      var grid = currentGrid();\n      if (grid) grid.classList.add('is-loading');\n\n      var fetchUrl = new URL(url.toString());\n      fetchUrl.searchParams.set('section_id', form.getAttribute('data-section-id'));\n\n      var id = ++seq;\n      fetch(fetchUrl.toString())\n        .then(function (response) { return response.text(); })\n        .then(function (html) {\n          if (id !== seq) return;\n          var doc = new DOMParser().parseFromString(html, 'text/html');\n          var open = openGroups();\n          swapAll(doc);\n          restoreGroups(open);\n          afterSwap(doc);\n          if (writeHistory !== false) {\n            window.history.replaceState(window.history.state, '', url.toString());\n          }\n        })\n        .catch(function () {\n          /* Fall back to a full navigation rather than stranding the shopper\n             on a grid stuck in its loading state. */\n          if (id === seq) window.location.href = url.toString();\n        });\n    }\n\n    /* ---------- Price ---------- */\n\n    /* Mirrors the slider (already two-way-synced with the Min/Max fields by the\n       theme's range module) into the hidden gte/lte inputs the form submits.\n       Both thumbs at the extremes means no price filter, so the inputs empty\n       and the params drop out of the serialised URL. */\n    function syncPrice(root) {\n      var min = root.querySelector('[data-range-min]');\n      var max = root.querySelector('[data-range-max]');\n      var gte = root.querySelector('[data-sf-price-gte]');\n      var lte = root.querySelector('[data-sf-price-lte]');\n      if (!min || !max || !gte || !lte) return;\n      var floor = parseInt(root.getAttribute('data-floor'), 10) || 0;\n      var ceiling = parseInt(root.getAttribute('data-ceiling'), 10) || 0;\n      var lo = parseInt(min.value, 10);\n      var hi = parseInt(max.value, 10);\n      gte.value = lo > floor ? String(lo) : '';\n      lte.value = hi < ceiling ? String(hi) : '';\n    }\n\n    /* ---------- Events ----------\n       Delegated, so controls swapped on every refresh keep working. */\n\n    document.addEventListener('change', function (e) {\n      if (!e.target.closest) return;\n      var form = e.target.closest('[data-shopify-filters]');\n      if (!form) return;\n      /* Sort still reloads the page via the drawer's own sort module -\n         accepted fallback behaviour, matching the desktop sort control. */\n      if (e.target.name === 'sort_by') return;\n\n      var price = e.target.closest('[data-sf-price]');\n      if (price) syncPrice(price);\n\n      refresh(buildUrl(form));\n    });\n\n    document.addEventListener('click', function (e) {\n      if (!e.target.closest) return;\n      var link = e.target.closest('[data-sf-remove], [data-sf-clear]');\n      if (!link) return;\n      e.preventDefault();\n      refresh(new URL(link.getAttribute('href'), window.location.origin));\n    });\n\n    document.addEventListener('submit', function (e) {\n      var form = e.target;\n      if (!form.hasAttribute || !form.hasAttribute('data-shopify-filters')) return;\n      e.preventDefault();\n      refresh(buildUrl(form));\n    });\n\n    /* Back/forward: re-fetch for the restored URL so the grid, chips and\n       facets match the history entry. */\n    window.addEventListener('popstate', function () {\n      if (!getForm()) return;\n      refresh(new URL(window.location.href), false);\n    });\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"suburb-suggestions\"] && !Shopify.designMode) return;\n  try {\n    /* Postcode-to-suburb suggestions, shared by the PDP store-locator block and\n     the store-locator page (#1190). See the LiquidDoc header in\n     snippets/suburb-suggestions.liquid for why this is shared rather than\n     copied. */\n  (function () {\n    if (window.__esSuburbSuggest) { return; }\n\n    /* Mirror of normaliseSuburb() in workers/api/src/lib/transit.ts and\n       scripts/build-transit-data.mjs. Used ONLY to decide whether Google has\n       already offered a suburb, so \"Mt Albert\" from Google suppresses \"Mount\n       Albert\" from us. If the worker's map gains an alias, add it here too or\n       the same suburb can appear twice. */\n    var ALIASES = {\n      ST: 'SAINT',\n      MT: 'MOUNT',\n      NTH: 'NORTH',\n      STH: 'SOUTH',\n      E: 'EAST',\n      W: 'WEST',\n      N: 'NORTH',\n      S: 'SOUTH'\n    };\n\n    function normalise(value) {\n      return String(value || '')\n        .toUpperCase()\n        .replace(/[^A-Z0-9]+/g, ' ')\n        .trim()\n        .split(' ')\n        .map(function (word) { return ALIASES[word] || word; })\n        .join(' ');\n    }\n\n    /* Is the shopper searching by postcode? Digits only, three or four of them,\n       returned zero-padded to the four digits the worker keys on - NZ shoppers\n       type \"600\" as readily as \"0600\", and Excel strips the leading zero from\n       the supply files too. Anything else (a suburb name, a street, a mix) is\n       not a postcode query and leaves the existing behaviour alone. */\n    function asPostcode(value) {\n      var raw = String(value || '').replace(/\\s+/g, '');\n      if (!/^\\d{3,4}$/.test(raw)) { return ''; }\n      var padded = raw.length === 3 ? '0' + raw : raw;\n      /* \"0000\" is not a real postcode in either market and only ever comes from\n         a shopper typing zeros, so it is not worth a request. */\n      return padded === '0000' ? '' : padded;\n    }\n\n    /* Suburbs for a postcode, from the worker. Resolves to [] on anything at\n       all going wrong - a missing url, a network error, a non-OK response, an\n       unknown postcode - because this only ever ADDS to Google's list, so the\n       honest failure is to add nothing. Cached per url+country+postcode for the\n       life of the page; the data is static. */\n    var cache = {};\n    function fetchSuburbs(transitUrl, country, padded) {\n      if (!transitUrl || !padded) { return Promise.resolve([]); }\n      var key = transitUrl + '|' + country + '|' + padded;\n      if (cache[key]) { return cache[key]; }\n      var url = transitUrl.replace(/\\/$/, '') + '/suburbs?postcode=' +\n        encodeURIComponent(padded) + '&country=' + encodeURIComponent(country);\n      cache[key] = fetch(url)\n        .then(function (r) { return r.ok ? r.json() : null; })\n        .then(function (body) {\n          return body && body.found && body.suburbs ? body.suburbs : [];\n        })\n        .catch(function () { return []; });\n      return cache[key];\n    }\n\n    /* The suburbs to APPEND, i.e. those Google has not already offered.\n       `googleNames` is whatever each surface can read off its own predictions -\n       the main text, which for a postcode query is the postcode itself and for\n       a suburb is the suburb name. Order is the worker's (alphabetical). */\n    function extras(googleNames, suburbs) {\n      var seen = {};\n      (googleNames || []).forEach(function (name) {\n        var k = normalise(name);\n        if (k) { seen[k] = true; }\n      });\n      var out = [];\n      (suburbs || []).forEach(function (name) {\n        var k = normalise(name);\n        if (!k || seen[k]) { return; }\n        seen[k] = true;\n        out.push(name);\n      });\n      return out;\n    }\n\n    window.__esSuburbSuggest = {\n      normalise: normalise,\n      asPostcode: asPostcode,\n      fetchSuburbs: fetchSuburbs,\n      extras: extras\n    };\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"text-icon\"] && !Shopify.designMode) return;\n  try {\n    (function () {\n    function update(root) {\n      var row = root.querySelector('.text-icon__row--m-carousel');\n      var bar = root.querySelector('.text-icon__progress');\n      var fill = root.querySelector('.text-icon__progress-fill');\n      if (!row || !bar || !fill) return;\n\n      var max = row.scrollWidth - row.clientWidth;\n      if (max <= 1) {\n        bar.hidden = true;\n        return;\n      }\n      bar.hidden = false;\n\n      var progress = row.scrollLeft / max;\n      if (progress < 0) progress = 0;\n      if (progress > 1) progress = 1;\n\n      fill.style.width = (progress * 100) + '%';\n    }\n\n    function init(root) {\n      if (root.dataset.tiInit === '1') return;\n      var row = root.querySelector('.text-icon__row--m-carousel');\n      if (!row) return;\n      root.dataset.tiInit = '1';\n      var run = function () { update(root); };\n      row.addEventListener('scroll', run, { passive: true });\n      window.addEventListener('resize', run);\n      run();\n    }\n\n    function initAll() {\n      var roots = document.querySelectorAll('[data-text-icon-carousel]');\n      for (var i = 0; i < roots.length; i++) init(roots[i]);\n    }\n\n    if (document.readyState === 'loading') {\n      document.addEventListener('DOMContentLoaded', initAll);\n    } else {\n      initAll();\n    }\n    document.addEventListener('shopify:section:load', initAll);\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"textarea\"] && !Shopify.designMode) return;\n  try {\n    document.querySelectorAll('[data-character-count]').forEach(function (field) {\n    var wrap = field.closest('.field');\n    var counter = wrap ? wrap.querySelector('[data-character-count-current]') : null;\n    if (!counter) return;\n    function update() { counter.textContent = field.value.length; }\n    field.addEventListener('input', update);\n    update();\n  });\n\n  document.querySelectorAll('[data-autogrow]').forEach(function (field) {\n    var oneLine = 0;\n    function measureBaseline() {\n      /* The 1-line scrollHeight (incl. a textarea's ~4px intrinsic slack) */\n      var v = field.value;\n      field.value = '';\n      field.style.height = 'auto';\n      oneLine = field.scrollHeight;\n      field.value = v;\n    }\n    function grow() {\n      field.style.height = 'auto';\n      var sh = field.scrollHeight;\n      /* Single line: let min-height settle it at the input's 30px. Grown lines\n         lose the 1-line slack, so add 3px back for the matching bottom gap. */\n      field.style.height = (sh > oneLine + 1 ? sh + 3 : sh) + 'px';\n    }\n    measureBaseline();\n    grow();\n    field.addEventListener('input', grow);\n    /* Re-measure once the web font has loaded - the fallback font's taller\n       line would otherwise bake in a wrong baseline/height on first paint */\n    if (document.fonts && document.fonts.ready) {\n      document.fonts.ready.then(function () { measureBaseline(); grow(); });\n    }\n  });\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"wishlist-notification\"] && !Shopify.designMode) return;\n  try {\n    class WishlistNotification extends HTMLElement {\n    connectedCallback() {\n      this.panel = this.querySelector('[data-wishlist-notification-panel]');\n      if (!this.panel) return;\n\n      this.DISPLAY_MS = 5000;\n      this.TRANSITION_MS = 200;\n\n      this.onDocumentClick = this.onDocumentClick.bind(this);\n      this.onKeydown = this.onKeydown.bind(this);\n      this.onPointerEnter = this.onPointerEnter.bind(this);\n      this.onPointerLeave = this.onPointerLeave.bind(this);\n\n      document.addEventListener('click', this.onDocumentClick);\n      document.addEventListener('keydown', this.onKeydown);\n      this.panel.addEventListener('pointerenter', this.onPointerEnter);\n      this.panel.addEventListener('pointerleave', this.onPointerLeave);\n      this.panel.addEventListener('focusin', this.onPointerEnter);\n      this.panel.addEventListener('focusout', this.onPointerLeave);\n\n      // theWishlist.io only builds `.toast-wishlist` after a successful save,\n      // so its insertion is the add-to-wishlist signal (see the snippet doc).\n      this.observer = new MutationObserver((mutations) => {\n        for (let i = 0; i < mutations.length; i++) {\n          const added = mutations[i].addedNodes;\n          for (let j = 0; j < added.length; j++) {\n            const node = added[j];\n            if (node.nodeType !== 1) continue;\n            if (node.classList.contains('toast-wishlist') || node.querySelector('.toast-wishlist')) {\n              this.show();\n              return;\n            }\n          }\n        }\n      });\n      this.observer.observe(document.body, { childList: true, subtree: true });\n    }\n\n    disconnectedCallback() {\n      document.removeEventListener('click', this.onDocumentClick);\n      document.removeEventListener('keydown', this.onKeydown);\n      if (this.observer) this.observer.disconnect();\n      clearTimeout(this.dismissTimer);\n      clearTimeout(this.hideTimer);\n    }\n\n    get open() {\n      return this.hasAttribute('open');\n    }\n\n    show() {\n      clearTimeout(this.hideTimer);\n      this.panel.hidden = false;\n      // Let the panel lay out before the opacity/transform transition starts.\n      requestAnimationFrame(() => this.setAttribute('open', ''));\n      this.scheduleDismiss();\n    }\n\n    hide() {\n      if (!this.open) return;\n      clearTimeout(this.dismissTimer);\n      this.removeAttribute('open');\n      this.hideTimer = setTimeout(() => {\n        this.panel.hidden = true;\n      }, this.TRANSITION_MS);\n    }\n\n    scheduleDismiss() {\n      clearTimeout(this.dismissTimer);\n      this.dismissTimer = setTimeout(() => this.hide(), this.DISPLAY_MS);\n    }\n\n    // Keep the tooltip up while the customer is reading it / tabbing the CTA.\n    onPointerEnter() {\n      clearTimeout(this.dismissTimer);\n    }\n\n    onPointerLeave() {\n      if (this.open) this.scheduleDismiss();\n    }\n\n    onDocumentClick(event) {\n      if (!this.open) return;\n      if (this.contains(event.target)) return;\n      this.hide();\n    }\n\n    onKeydown(event) {\n      if (event.key === 'Escape' && this.open) this.hide();\n    }\n  }\n\n  if (!customElements.get('wishlist-notification')) {\n    customElements.define('wishlist-notification', WishlistNotification);\n  }\n  } catch(e) { console.error(e); }\n})();\n\n(function() {\n  if (!__snippets__[\"zendesk-widget\"] && !Shopify.designMode) return;\n  try {\n    /* Open the widget from anywhere in the theme: any control carrying\n     data-zendesk-open. Delegated on document, so it also covers markup that is\n     injected or revealed after load - the PDP drawer tabs, for one.\n\n     typeof guard rather than a bare \"if (zE)\": when the embed has not loaded, zE\n     is an UNDECLARED identifier and the bare check throws a ReferenceError that\n     would kill the handler silently. Messaging first (newer edition), Classic as\n     the fallback - the account can be on either. preventDefault runs before the\n     guard so a link never jumps to its href when the widget is missing. */\n  (function () {\n    document.addEventListener('click', function (event) {\n      var trigger = event.target.closest && event.target.closest('[data-zendesk-open]');\n      if (!trigger) return;\n      event.preventDefault();\n      if (typeof zE !== 'function') return;\n      /* A trigger can sit inside a modal - the PDP drawer tabs are a showModal()\n         <dialog>, so they live in the TOP LAYER and paint over the widget\n         whatever its z-index. Nothing can out-stack that, so close the dialog and\n         let the chat come up on the page behind it. Closed only once the widget\n         is known to be there, so a missing embed can't shut the panel for\n         nothing, and via native .close() so each dialog's own close handler still\n         restores scroll and focus. */\n      var modal = trigger.closest('dialog[open]');\n      if (modal && typeof modal.close === 'function') modal.close();\n      try {\n        zE('messenger', 'open');\n      } catch (messagingErr) {\n        try {\n          zE('webWidget', 'open');\n        } catch (classicErr) {\n          /* Neither API target valid - widget misconfigured. No-op. */\n        }\n      }\n    });\n  })();\n\n  /* Skin the Zendesk launcher bubble.\n\n     The launcher is an iframe, but Zendesk builds its document in-page so it is\n     SAME-ORIGIN and reachable - we inject one stylesheet into it rather than\n     trying (and failing) to reach the button from the parent document.\n\n     A stylesheet, not inline styles: the button is React-rendered and re-renders\n     on hover/open, which would wipe inline styles. Zendesk's own colour rule\n     (a styled-components class) carries no !important, so an !important rule\n     here beats it regardless of specificity, and survives every re-render.\n\n     Colours are read from the theme's CSS custom properties at runtime - the\n     iframe is a separate document, so var() would not resolve inside it. */\n  (function () {\n    if (!document.getElementById('ze-snippet')) return;\n\n    var SIZE = 46;\n    var root = getComputedStyle(document.documentElement);\n    var bg = (root.getPropertyValue('--color-warm-grey') || '').trim() || '#70675b';\n    var fg = (root.getPropertyValue('--color-sand') || '').trim() || '#ffffff';\n\n    var css =\n      'html,body{background:transparent!important;}' +\n      'body>div,body>div>div{width:' + SIZE + 'px!important;height:' + SIZE + 'px!important;' +\n      'background:transparent!important;}' +\n      'button{width:' + SIZE + 'px!important;height:' + SIZE + 'px!important;' +\n      'min-width:0!important;min-height:0!important;' +\n      'background-color:' + bg + '!important;border-color:' + bg + '!important;' +\n      'border-radius:50%!important;color:' + fg + '!important;}' +\n      'button svg{fill:currentColor!important;}';\n\n    function skin() {\n      var frame = document.getElementById('launcher');\n      if (!frame) return false;\n      var doc = frame.contentDocument;\n      /* No head yet = the frame exists but Zendesk has not written into it. */\n      if (!doc || !doc.head) return false;\n      if (doc.getElementById('es-zd-launcher')) return true;\n      var style = doc.createElement('style');\n      style.id = 'es-zd-launcher';\n      style.textContent = css;\n      doc.head.appendChild(style);\n      return true;\n    }\n\n    /* A heartbeat rather than a MutationObserver, deliberately.\n\n       Zendesk mounts the launcher asynchronously, then REWRITES the iframe's\n       document once the widget is ready - which silently discards a stylesheet\n       injected into the placeholder. That rewrite happens inside the frame, so\n       it is not a mutation of this document and an observer on body never sees\n       it (tried; the bubble stayed black). The frame is also torn down and\n       rebuilt as the messenger opens and closes.\n\n       So: re-check once a second and re-inject if the stylesheet has gone. Each\n       tick is two getElementById calls and an early return, which is cheaper\n       than observing a subtree that mutates on every carousel tick. */\n    skin();\n    setInterval(skin, 1000);\n  })();\n  } catch(e) { console.error(e); }\n})();\n\n})();\n"],
  "mappings": "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",
  "names": ["tpl", "node", "field", "btn", "esQuantitySync"]
}
