{"webLayers":[],"experiments":[],"constantManagedTags":[{"uses_overlay":false,"type":"js","parametrized_definition":"const pdpWeblayerId = \"6a1f4880adfc414176f42093\";\nconst searchWeblayerId = \"6a0de5998e98f43051f2473d\";\n\nconst loadClarityUtils = async () =\u003e {\n  const url = 'https://unpkg.com/@bloomreach/clarity-utils@1.0.8/dist/index.global.js'\n  for (let attempt = 1; attempt \u003c= 5; attempt++) {\n    try {\n      await new Promise((resolve, reject) =\u003e {\n        const s = document.createElement('script')\n        s.src = url\n        s.onload = resolve\n        s.onerror = () =\u003e reject(new Error(`Failed to load ${url}`))\n        document.head.appendChild(s)\n      })\n      return\n    } catch (err) {\n      console.warn(`clarity-utils load attempt ${attempt}/5 failed`, err)\n      if (attempt === 5) throw err\n      await new Promise(r =\u003e setTimeout(r, 200 * attempt))\n    }\n  }\n}\n\nconst clarityUtilsLoaded = loadClarityUtils()\n\nwindow.CLARITY_HELPER = {\n\t...(window.CLARITY_HELPER || {}),\n\tinvokePDP: () =\u003e {\n\t  window.CLARITY.setSource(pdpWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n\t},\n    invokeSearchHubOrch: input =\u003e {\n\t  window.CLARITY.setSource(searchWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n      window.CLARITY.call('user_send_message', {\n        input,\n        type: 'text',\n        force: true,\n        source: 'DEFAULT',\n      });\n\t},\n\tisSearch: async (input, config) =\u003e {\n\t  if (!input?.trim()) return;\n\t  console.log('clarity is search', input, config)\n\t  await clarityUtilsLoaded\n\t  const result = window.clarityUtils.isSearch(input, { mode: 'score', ...(config ?? {}) })\n\t  const logger = window.brweb ?? window.exponea\n\t  logger.track('clarity', {\n\t  \taction: 'search_orchestrator',\n\t  \tsearch_string: input,\n\t  \tis_conversational: !result\n\t  });\n\t  return result;\n\t},\n}","trigger":{"include_pages":[{"url":"/en-us","type":"contains"}],"exclude_pages":null},"_id":"6a0de5998e98f43051f24751"},{"uses_overlay":false,"type":"js","parametrized_definition":"// A customized MiniPDP that combines tblBaseMiniPDP's variant/dimension UI\n// with timberlandATC's stock check + add-to-cart, and adds an \"Add to Cart\"\n// footer button.\n//\n// Behavior:\n//   - On product change, fetches the product inventory once. Out-of-stock\n//     variants render their dimension chips as `is-disabled` (greyed out and\n//     diagonal-striped), but remain CLICKABLE so the consumer can still\n//     navigate to the variant. The Add-to-Cart button switches to a disabled\n//     \"Out of Stock\" state when the active variant is out of stock.\n//   - The Add-to-Cart button posts to Timberland's cart API, persisting the\n//     cartId in localStorage so the next add appends to the same cart.\n//\n// CSS: load tblCusotmized.css — it is self-contained (base layout + ATC\n// footer additions). Do NOT also load tblBaseMiniPDP.css.\n//\n// Usage: load this file as a plain script (not a module) alongside the two\n// CSS files. It registers tblCusotmized + tblCusotmizedATC on\n// window.CLARITY_GLOBAL_CONFIG.\n\nconst ORIGIN = location.origin;\n\nconst DIMENSION_NAMES = ['color', 'size', 'length', 'width', 'material', 'style', 'flavor']\n\nconst FAKE_LENGTHS = ['Medium', 'Wide']\n\n// ATC animation: progress bar fills over ATC_ANIMATION_MS while the request is\n// in flight; the result label (View Cart / Failed) shows for ATC_RESET_MS, then\n// the button reverts to \"Add to Cart\".\nconst ATC_ANIMATION_MS = 1800\nconst ATC_RESET_MS = 3000\n\n\nconst injectFakeLengthDimension = product =\u003e {\n  if (!product?.variants?.length) return product\n  if (product.variants[0]?.length != null \u0026\u0026 product.variants[0].length !== '') return product\n  const augmented = []\n  product.variants.forEach(v =\u003e {\n    FAKE_LENGTHS.forEach(length =\u003e augmented.push({ ...v, length }))\n  })\n  return { ...product, variants: augmented }\n}\n\n// === Timberland ATC helpers (mirrors timberlandATC.js) ===\n\nconst getChatId = () =\u003e {\n  try {\n    const raw = localStorage.getItem('BR:CLARITY') ?? sessionStorage.getItem('BR:CLARITY') ?? '{}'\n    const chatIdStore = JSON.parse(raw)?.chatId ?? {}\n    const version = Object.keys(chatIdStore)[0]\n    return (version \u0026\u0026 chatIdStore[version]?.CHAT_ID) ?? crypto.randomUUID()\n  } catch {\n    return crypto.randomUUID()\n  }\n}\n\nconst getLocale = () =\u003e {\n  const seg = window.location.pathname.split('/').filter(Boolean)[0] ?? 'en-us'\n  return /^[a-z]{2}-[a-z]{2}$/.test(seg) ? seg : 'en-us'\n}\n\nconst getCartStorageKey = locale =\u003e `cart_${locale.slice(-2).toUpperCase()}`\n\n// localStorage stores a JSON object like { basketId, ... }. Read/write the\n// basketId field; tolerate legacy plain-string values on read.\nconst getCartId = locale =\u003e {\n  const raw = localStorage.getItem(getCartStorageKey(locale))\n  if (!raw) return ''\n  try {\n    const parsed = JSON.parse(raw)\n    return parsed?.basketId ?? ''\n  } catch {\n    return raw\n  }\n}\n\nconst setCartId = (locale, cartId) =\u003e {\n  if (!cartId) return\n  const key = getCartStorageKey(locale)\n  let existing = {}\n  try {\n    existing = JSON.parse(localStorage.getItem(key) ?? '{}') ?? {}\n    if (typeof existing !== 'object') existing = {}\n  } catch {\n    existing = {}\n  }\n  localStorage.setItem(key, JSON.stringify({ ...existing, basketId: cartId }))\n}\n\nconst getProductIdFromVariantId = id =\u003e (id?.includes('TB:') ? id.split(':').slice(0, 3).join('') : id)\n\nconst tblHeaders = locale =\u003e {\n  const chatId = getChatId()\n  const country = locale.slice(-2).toUpperCase()\n  const language = locale.slice(0, 2).toLowerCase()\n  return {\n    'x-transaction-id': chatId,\n    'x-correlation-id': chatId,\n    channel: 'ECOMM',\n    locale: `${language}_${country}`,\n    brand: 'TBL',\n    siteid: `TBL-${country}`,\n    source: 'ECOM15',\n    region: country === 'US' || country === 'CA' ? 'NORA' : 'EMEA',\n    'content-type': 'application/json',\n  }\n}\n\n// One inventory call returns stock for every variant of the product, keyed by\n// variant id — fetch once per product instead of once per variant.\nconst fetchAllVariantStock = async (productId, locale) =\u003e {\n  const res = await fetch(`${ORIGIN}/api/products/v2/products/${productId}/inventory?locale=${locale}`, {\n    headers: tblHeaders(locale),\n  })\n  if (!res.ok) throw new Error(`Inventory request failed: ${res.status}`)\n  const body = await res.json()\n  return body?.variants ?? {}\n}\n\nconst fetchVariantStock = async (variantId, locale) =\u003e {\n  const productId = getProductIdFromVariantId(variantId)\n  const variants = await fetchAllVariantStock(productId, locale)\n  return variants?.[variantId]\n}\n\nconst isVariantInStock = stockEntry =\u003e !!stockEntry \u0026\u0026 stockEntry.inStock \u0026\u0026 stockEntry.quantity \u003e 0\n\nconst postAddToCart = async a =\u003e {\n  const hasCart = !!a.cartId\n  const path = hasCart ? '/api/cart/v1/item' : '/api/cart/v1/cartWithItem'\n  const res = await fetch(`${ORIGIN}${path}?locale=${a.locale}`, {\n    method: 'POST',\n    headers: tblHeaders(a.locale),\n    body: JSON.stringify({\n      cartId: a.cartId,\n      maxQty: 10,\n      productId: a.productId,\n      qty: 1,\n      upc: a.upc,\n    }),\n  })\n  if (!res.ok) throw new Error(`Add-to-cart request failed: ${res.status}`)\n  return res.json()\n}\n\nconst addVariantToCart = async variant =\u003e {\n  const variantId = variant?.id\n  const upc = variant?.upc?.[0]\n  if (!variantId) throw new Error('missing variant id')\n  if (!upc) throw new Error('missing upc on variant')\n  const locale = getLocale()\n  const cartId = getCartId(locale)\n  const result = await postAddToCart({ cartId, productId: variantId, upc, locale })\n  const newCartId = result?.cartId ?? result?.id\n  if (!cartId \u0026\u0026 newCartId) setCartId(locale, newCartId)\n  return result\n}\n\n// Standalone ATC function — mirrors timberlandATC's contract (fetch stock,\n// bail if out of stock, post to cart). Always resolves with a result object\n// of shape { status: 'success' | 'failed', message?: string } so callers\n// (e.g. webChatPlugin's CocoConfig.fn.addToCart) can react to the outcome.\nconst tblCusotmizedATC = async product =\u003e {\n  console.log('[AMA] Clarity - Customized - tblCusotmizedATC', product)\n  const variantId = product?.id\n  const upc = product?.upc?.[0]\n  if (!variantId) {\n    console.warn('[tblCusotmizedATC] missing product id')\n    return { status: 'failed', message: 'missing product id' }\n  }\n  if (!upc) {\n    console.warn('[tblCusotmizedATC] missing upc on product', product)\n    return { status: 'failed', message: 'missing upc on product' }\n  }\n  try {\n    const stock = await fetchVariantStock(variantId, getLocale())\n    if (!isVariantInStock(stock)) {\n      console.warn('[tblCusotmizedATC] variant out of stock', variantId, stock)\n      return { status: 'failed', message: 'variant out of stock' }\n    }\n    await addVariantToCart(product)\n    return { status: 'success' }\n  } catch (err) {\n    console.error('[tblCusotmizedATC]', err)\n    return { status: 'failed', message: err?.message ?? 'add to cart failed' }\n  }\n}\n\n// === shared utils (mirrors tblBaseMiniPDP.js) ===\n\nconst toTitleCase = str =\u003e\n  String(str || '')\n    .split(' ')\n    .map(w =\u003e (w.length ? w[0].toUpperCase() + w.slice(1).toLowerCase() : w))\n    .join(' ')\n\nconst formatPrice = (amount, currency) =\u003e {\n  if (amount == null || amount === '') return ''\n  try {\n    return new Intl.NumberFormat('en-US', {\n      style: 'currency',\n      currency: currency || 'USD',\n    }).format(amount)\n  } catch {\n    return `${currency || ''} ${amount}`\n  }\n}\n\nconst isPriceHigher = (a, b) =\u003e {\n  const x = parseFloat(a)\n  const y = parseFloat(b)\n  if (Number.isNaN(x) || Number.isNaN(y)) return false\n  return x \u003e y\n}\n\n// True only when the trimmed string parses as a finite number AND has no\n// trailing non-numeric junk (so \"8\" / \"8.5\" sort numerically, but \"8W\" /\n// \"Medium\" stay as strings).\nconst isPureNumber = value =\u003e {\n  if (typeof value === 'number') return Number.isFinite(value)\n  const str = String(value ?? '').trim()\n  if (str === '') return false\n  return !Number.isNaN(Number(str)) \u0026\u0026 /^-?\\d+(\\.\\d+)?$/.test(str)\n}\n\nconst sortDimensionValues = values =\u003e {\n  if (values.length \u003c= 1) return values\n  if (values.every(isPureNumber)) {\n    return [...values].sort((a, b) =\u003e Number(a) - Number(b))\n  }\n  return values\n}\n\nconst generateDimensions = variants =\u003e {\n  if (!variants?.length) return []\n  const out = []\n  DIMENSION_NAMES.forEach(name =\u003e {\n    const allHaveValue = variants.every(v =\u003e v[name] != null \u0026\u0026 v[name] !== '')\n    if (!allHaveValue) return\n    const values = []\n    variants.forEach(v =\u003e {\n      if (!values.includes(v[name])) values.push(v[name])\n    })\n    if (values.length \u003e 1) out.push({ name, values: sortDimensionValues(values) })\n  })\n  return out\n}\n\nconst findExactVariant = (variants, criteria) =\u003e {\n  if (!variants?.length) return undefined\n  return variants.find(v =\u003e Object.keys(criteria).every(k =\u003e v[k] === criteria[k]))\n}\n\nconst tblCusotmized = (el, initialProps) =\u003e {\n  let props = { ...initialProps, product: injectFakeLengthDimension(initialProps.product) }\n  let dimensions = []\n  let activated = {}\n  // stockMap is { [variantId]: stockEntry }; stockLoaded gates display logic\n  // so chips/buttons aren't prematurely flagged out-of-stock before the\n  // inventory call resolves. stockProductId guards against stale responses\n  // when the user flips between products faster than the network.\n  let stockMap = {}\n  let stockLoaded = false\n  let stockProductId = null\n  // ATC phase machine:\n  //   'idle'    → default; button reads \"Add to Cart\"\n  //   'pending' → progress-bar animation running + ATC request in flight\n  //   'success' → animation done + request succeeded; button reads \"View Cart\"\n  //               (clickable → cart page); auto-resets to 'idle' after ATC_RESET_MS\n  //   'failed'  → animation done + request failed; button reads \"Failed\";\n  //               auto-resets to 'idle' after ATC_RESET_MS\n  // atcGen invalidates in-flight requests when the user changes variant\n  // mid-flight so a stale resolve can't flip the new variant's button.\n  let atcPhase = 'idle'\n  let atcResetTimerId = null\n  let atcGen = 0\n\n  const cancelAtcResetTimer = () =\u003e {\n    if (atcResetTimerId) {\n      clearTimeout(atcResetTimerId)\n      atcResetTimerId = null\n    }\n  }\n\n  const resetAtcStatus = () =\u003e {\n    atcGen += 1\n    cancelAtcResetTimer()\n    atcPhase = 'idle'\n  }\n\n  // Toast container lives inside the MiniPDP root so it's positioned relative\n  // to the panel, not the page viewport. Created lazily on first showAtcToast.\n  let atcToastContainer = null\n  const ensureAtcToastContainer = () =\u003e {\n    if (atcToastContainer \u0026\u0026 root.contains(atcToastContainer)) return atcToastContainer\n    atcToastContainer = document.createElement('div')\n    atcToastContainer.className = 'tbl-customized-toast-container'\n    root.appendChild(atcToastContainer)\n    return atcToastContainer\n  }\n  const showAtcToast = (message, opts) =\u003e {\n    const container = ensureAtcToastContainer()\n    const toast = document.createElement('div')\n    toast.className = 'tbl-customized-toast'\n    toast.textContent = message\n    container.appendChild(toast)\n    requestAnimationFrame(() =\u003e toast.classList.add('is-visible'))\n    const duration = opts?.duration ?? 2500\n    setTimeout(() =\u003e {\n      toast.classList.remove('is-visible')\n      setTimeout(() =\u003e toast.remove(), 250)\n    }, duration)\n  }\n\n  const root = document.createElement('div')\n  root.id = 'tbl-base-mini-pdp-root'\n  root.className = 'tbl-base-mini-pdp tbl-customized-mini-pdp'\n  root.innerHTML = `\n    \u003cdiv class=\"tbl-base-mini-pdp__top-bar\"\u003e\n      \u003cbutton class=\"tbl-base-mini-pdp__icon-btn\" data-action=\"close\" type=\"button\"\u003e\n        Close\n      \u003c/button\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"tbl-base-mini-pdp__scroll\"\u003e\n      \u003cdiv class=\"tbl-base-mini-pdp__hero\"\u003e\n        \u003cimg class=\"tbl-base-mini-pdp__image\" alt=\"\" /\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"tbl-base-mini-pdp__details\"\u003e\n        \u003cdiv class=\"tbl-base-mini-pdp__heading\"\u003e\n          \u003cdiv class=\"tbl-base-mini-pdp__name-block\"\u003e\n            \u003cspan class=\"tbl-base-mini-pdp__title\"\u003e\u003c/span\u003e\n            \u003cbutton class=\"tbl-base-mini-pdp__view\" data-action=\"view\" type=\"button\" hidden\u003eView Product\u003c/button\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"tbl-base-mini-pdp__price-row is-hidden\"\u003e\n            \u003cspan class=\"tbl-base-mini-pdp__price\"\u003e\u003c/span\u003e\n            \u003cspan class=\"tbl-base-mini-pdp__original-price is-hidden\"\u003e\u003c/span\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"tbl-base-mini-pdp__dimensions\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"tbl-customized-mini-pdp__atc-container\"\u003e\n        \u003cbutton class=\"tbl-customized-mini-pdp__atc-btn\" data-action=\"atc\" type=\"button\"\u003e\n          \u003cspan class=\"tbl-customized-mini-pdp__atc-progress\"\u003e\u003c/span\u003e\n          \u003cspan class=\"tbl-customized-mini-pdp__atc-label\"\u003eAdd to Cart\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  `\n  el.appendChild(root)\n\n  const refs = {\n    root,\n    image: root.querySelector('.tbl-base-mini-pdp__image'),\n    title: root.querySelector('.tbl-base-mini-pdp__title'),\n    viewBtn: root.querySelector('[data-action=\"view\"]'),\n    priceRow: root.querySelector('.tbl-base-mini-pdp__price-row'),\n    price: root.querySelector('.tbl-base-mini-pdp__price'),\n    originalPrice: root.querySelector('.tbl-base-mini-pdp__original-price'),\n    dimensions: root.querySelector('.tbl-base-mini-pdp__dimensions'),\n    atcBtn: root.querySelector('[data-action=\"atc\"]'),\n    atcLabel: root.querySelector('.tbl-customized-mini-pdp__atc-label'),\n    atcProgress: root.querySelector('.tbl-customized-mini-pdp__atc-progress'),\n  }\n\n  // Treat variants as available until inventory loads to avoid flashing all\n  // chips disabled on first paint.\n  const isVariantAvailable = variantId =\u003e {\n    if (!stockLoaded) return true\n    return isVariantInStock(stockMap[variantId])\n  }\n\n  const getActiveVariant = () =\u003e {\n    const product = props.product\n    const selected = props.selectedVariant\n    if (selected) {\n      const merged = {}\n      Object.keys(product || {}).forEach(k =\u003e {\n        if (k === 'variants') return\n        merged[k] = product[k]\n      })\n      Object.keys(selected).forEach(k =\u003e {\n        if (selected[k] !== undefined \u0026\u0026 selected[k] !== null \u0026\u0026 selected[k] !== '') merged[k] = selected[k]\n      })\n      return merged\n    }\n    return product || {}\n  }\n\n  const buildDimensionsDOM = () =\u003e {\n    refs.dimensions.innerHTML = ''\n    dimensions.forEach(dim =\u003e {\n      const row = document.createElement('div')\n      row.className = `tbl-base-mini-pdp__dimension-row tbl-base-mini-pdp__dimension--${dim.name.toLowerCase()}`\n      row.dataset.dimensionName = dim.name\n\n      const label = document.createElement('div')\n      label.className = 'tbl-base-mini-pdp__dimension-label'\n      label.textContent = toTitleCase(dim.name)\n      row.appendChild(label)\n\n      const grid = document.createElement('div')\n      grid.className = 'tbl-base-mini-pdp__chip-grid'\n      dim.values.forEach(value =\u003e {\n        const chip = document.createElement('button')\n        chip.type = 'button'\n        chip.className = 'tbl-base-mini-pdp__chip'\n        chip.dataset.dimensionName = dim.name\n        chip.dataset.dimensionValue = String(value)\n        chip.setAttribute('aria-pressed', 'false')\n        chip.textContent = toTitleCase(String(value))\n        grid.appendChild(chip)\n      })\n      row.appendChild(grid)\n      refs.dimensions.appendChild(row)\n    })\n  }\n\n  // Whether the dimension combo resolves to an actual variant. Stock is NOT\n  // considered here on purpose — out-of-stock variants must remain selectable\n  // so the consumer can navigate to them (the ATC button then renders as\n  // \"Out of Stock\"). isApplicable gates click handling; visual disabled is\n  // computed separately.\n  const isApplicable = (name, value) =\u003e\n    !!findExactVariant(props.product?.variants, { ...activated, [name]: value })\n\n  const syncActiveChips = () =\u003e {\n    const chips = refs.dimensions.querySelectorAll('.tbl-base-mini-pdp__chip')\n    chips.forEach(chip =\u003e {\n      const name = chip.dataset.dimensionName\n      const value = chip.dataset.dimensionValue\n      const active = String(activated[name]) === value\n      const target = findExactVariant(props.product?.variants, { ...activated, [name]: value })\n      const applicable = !!target\n      const inStock = target ? isVariantAvailable(target.id) : false\n      const disabled = !active \u0026\u0026 (!applicable || !inStock)\n      chip.classList.toggle('is-active', active)\n      chip.classList.toggle('is-disabled', disabled)\n      chip.setAttribute('aria-pressed', active ? 'true' : 'false')\n      chip.setAttribute('aria-disabled', disabled ? 'true' : 'false')\n    })\n  }\n\n  const setHidden = (node, hidden) =\u003e {\n    node.classList.toggle('is-hidden', hidden)\n  }\n\n  const syncAtcButton = () =\u003e {\n    const v = getActiveVariant()\n    const variantId = v?.id\n    const outOfStock = stockLoaded \u0026\u0026 !!variantId \u0026\u0026 !isVariantAvailable(variantId)\n    let label\n    let disabled\n    if (atcPhase === 'pending') {\n      label = 'Add to Cart'\n      disabled = true\n    } else if (atcPhase === 'success') {\n      label = 'View Cart'\n      disabled = false\n    } else if (atcPhase === 'failed') {\n      label = 'Failed'\n      disabled = true\n    } else if (outOfStock) {\n      label = 'Out of Stock'\n      disabled = true\n    } else {\n      label = 'Add to Cart'\n      disabled = false\n    }\n    // Pending phase keeps the disabled attribute (so the click doesn't re-fire)\n    // but skips the is-disabled class so the button stays at full opacity and\n    // the red progress bar reads cleanly.\n    refs.atcBtn.classList.toggle('is-disabled', disabled \u0026\u0026 atcPhase !== 'pending')\n    refs.atcBtn.disabled = disabled\n    if (refs.atcLabel) refs.atcLabel.textContent = label\n    else refs.atcBtn.textContent = label\n\n    const progress = refs.atcProgress\n    if (progress) {\n      // 'pending' is set up by handleAddToCart (it triggers the width transition\n      // on its own to guarantee a from→to repaint); only handle the resting\n      // states here so re-syncs don't reset an in-flight animation.\n      if (atcPhase === 'success' || atcPhase === 'failed') {\n        progress.classList.remove('is-animating')\n        progress.classList.add('is-filled')\n      } else if (atcPhase === 'idle') {\n        progress.classList.remove('is-animating', 'is-filled')\n      }\n    }\n  }\n\n  const syncVariantContent = () =\u003e {\n    const v = getActiveVariant()\n\n    if (v.image \u0026\u0026 refs.image.src !== v.image) refs.image.src = v.image\n    refs.image.alt = v.title || ''\n\n    refs.title.textContent = v.title || ''\n\n    if (v.url) {\n      refs.viewBtn.hidden = false\n      refs.viewBtn.dataset.url = v.url\n    } else {\n      refs.viewBtn.hidden = true\n      delete refs.viewBtn.dataset.url\n    }\n\n    const priceStr = formatPrice(v.price, v.currency)\n    refs.price.textContent = priceStr\n    setHidden(refs.priceRow, !priceStr)\n\n    const originalStr = formatPrice(v.originalPrice, v.currency)\n    const showOriginal = !!originalStr \u0026\u0026 isPriceHigher(v.originalPrice, v.price)\n    refs.originalPrice.textContent = showOriginal ? originalStr : ''\n    setHidden(refs.originalPrice, !showOriginal)\n\n    syncAtcButton()\n  }\n\n  const initActivatedFromProps = () =\u003e {\n    activated = {}\n    const variants = props.product?.variants ?? []\n    if (!variants.length) return\n    const source = props.selectedVariant ?? variants[0]\n    dimensions.forEach(dim =\u003e {\n      activated[dim.name] = source?.[dim.name] ?? dim.values[0]\n    })\n  }\n\n  const chooseDimension = (name, value) =\u003e {\n    const variants = props.product?.variants ?? []\n    if (!variants.length) return\n    if (!isApplicable(name, value)) return\n    const target = findExactVariant(variants, { ...activated, [name]: value })\n    if (!target) return\n    if (stockLoaded \u0026\u0026 !isVariantAvailable(target.id)) return\n    activated[name] = value\n    syncActiveChips()\n    const previousId = props.selectedVariant?.id\n    props = { ...props, selectedVariant: target }\n    if (target.id !== previousId) resetAtcStatus()\n    syncVariantContent()\n    if (target.id \u0026\u0026 target.id !== previousId) {\n      props.onVariantSelect?.(target.id)\n    }\n  }\n\n  // Walk the cartesian product of dimension values in their sorted order\n  // (dimensions[0].values × dimensions[1].values × ...) and return the first\n  // combination that resolves to an in-stock variant. With dimensions\n  // [size, length], this checks size[0]+length[0], size[0]+length[1], …,\n  // size[1]+length[0], … in that order.\n  const findFirstAvailableVariant = () =\u003e {\n    const variants = props.product?.variants ?? []\n    if (!variants.length) return undefined\n    if (!dimensions.length) return variants.find(v =\u003e isVariantAvailable(v.id))\n\n    let found\n    const walk = (idx, criteria) =\u003e {\n      if (found) return\n      if (idx === dimensions.length) {\n        const v = findExactVariant(variants, criteria)\n        if (v \u0026\u0026 isVariantAvailable(v.id)) found = v\n        return\n      }\n      const dim = dimensions[idx]\n      for (const val of dim.values) {\n        if (found) return\n        walk(idx + 1, { ...criteria, [dim.name]: val })\n      }\n    }\n    walk(0, {})\n    return found\n  }\n\n  // After inventory loads, if the activated combo points at an out-of-stock\n  // variant, jump to the first in-stock variant so the user lands on\n  // something actually buyable.\n  const ensureInStockSelection = () =\u003e {\n    if (!stockLoaded) return\n    const variants = props.product?.variants ?? []\n    if (!variants.length) return\n    const current = findExactVariant(variants, activated)\n    if (current \u0026\u0026 isVariantAvailable(current.id)) return\n    const firstAvailable = findFirstAvailableVariant()\n    if (!firstAvailable) return\n    dimensions.forEach(dim =\u003e {\n      const v = firstAvailable[dim.name]\n      if (v !== undefined \u0026\u0026 v !== null) activated[dim.name] = v\n    })\n    const previousId = props.selectedVariant?.id\n    props = { ...props, selectedVariant: firstAvailable }\n    if (firstAvailable.id !== previousId) resetAtcStatus()\n    syncActiveChips()\n    syncVariantContent()\n    if (firstAvailable.id \u0026\u0026 firstAvailable.id !== previousId) {\n      props.onVariantSelect?.(firstAvailable.id)\n    }\n  }\n\n  const loadStockForCurrentProduct = async () =\u003e {\n    console.log('[AMA] Clarity - Customized - loadStockForCurrentProduct')\n    const variants = props.product?.variants ?? []\n    if (!variants.length) return\n    const sampleId = props.selectedVariant?.id ?? variants.find(v =\u003e v.id)?.id\n    if (!sampleId) return\n    const productId = getProductIdFromVariantId(sampleId)\n    if (!productId || productId === stockProductId) return\n    stockProductId = productId\n    stockLoaded = false\n    stockMap = {}\n    syncActiveChips()\n    syncAtcButton()\n    try {\n      const stock = await fetchAllVariantStock(productId, getLocale())\n      // Bail if the user changed product mid-flight.\n      if (stockProductId !== productId) return\n      stockMap = stock\n      stockLoaded = true\n      ensureInStockSelection()\n      syncActiveChips()\n      syncAtcButton()\n    } catch (err) {\n      console.error('[tblCusotmized] stock fetch failed', err)\n    }\n  }\n\n  const fullRender = () =\u003e {\n    resetAtcStatus()\n    dimensions = generateDimensions(props.product?.variants)\n    buildDimensionsDOM()\n    const variants = props.product?.variants ?? []\n    // On product change always start at variants[0] — any selectedVariant\n    // passed by the parent is ignored because it may be stale or from a\n    // different product. Once inventory loads, ensureInStockSelection jumps\n    // to the first in-stock variant.\n    if (variants.length) {\n      props = { ...props, selectedVariant: variants[0] }\n    }\n    initActivatedFromProps()\n    syncActiveChips()\n    syncVariantContent()\n    if (variants[0]?.id) props.onVariantSelect?.(variants[0].id)\n    loadStockForCurrentProduct()\n  }\n\n  const startAtcProgressAnimation = () =\u003e {\n    const progress = refs.atcProgress\n    if (!progress) return\n    progress.classList.remove('is-animating', 'is-filled')\n    // Force reflow so the next class change actually triggers a transition.\n    void progress.offsetWidth\n    progress.classList.add('is-animating')\n  }\n\n  const handleAddToCart = async () =\u003e {\n    if (atcPhase !== 'idle') return\n    const v = getActiveVariant()\n    if (!v?.id) return\n    if (stockLoaded \u0026\u0026 !isVariantAvailable(v.id)) return\n\n    cancelAtcResetTimer()\n    const myGen = ++atcGen\n    atcPhase = 'pending'\n    syncAtcButton()\n    startAtcProgressAnimation()\n\n    const animationPromise = new Promise(resolve =\u003e setTimeout(resolve, ATC_ANIMATION_MS))\n    // Re-check stock at click time (same flow as tblCusotmizedATC) so a stale\n    // cached map doesn't let the user add an item that just sold out.\n    const requestPromise = (async () =\u003e {\n      try {\n        return await tblCusotmizedATC(v)\n      } catch {\n        return { status: 'failed' }\n      }\n    })()\n\n    const [, result] = await Promise.all([animationPromise, requestPromise])\n    if (myGen !== atcGen) return\n\n    const success = result?.status === 'success'\n    atcPhase = success ? 'success' : 'failed'\n    syncAtcButton()\n    showAtcToast(success ? 'Added!' : 'Failed to add to cart', { duration: ATC_RESET_MS })\n\n    atcResetTimerId = setTimeout(() =\u003e {\n      atcResetTimerId = null\n      if (myGen !== atcGen) return\n      atcPhase = 'idle'\n      syncAtcButton()\n    }, ATC_RESET_MS)\n  }\n\n  const goToCheckout = () =\u003e {\n    window.location.href = `${ORIGIN}/${getLocale()}/cart`\n  }\n\n  root.addEventListener('click', e =\u003e {\n    const target = e.target\n    if (!(target instanceof Element)) return\n\n    const closeBtn = target.closest('[data-action=\"close\"]')\n    if (closeBtn) {\n      props.onClose?.()\n      return\n    }\n\n    const viewBtn = target.closest('[data-action=\"view\"]')\n    if (viewBtn) {\n      const url = viewBtn.dataset.url\n      if (url) window.open(url, '_self')\n      return\n    }\n\n    const atcBtn = target.closest('[data-action=\"atc\"]')\n    if (atcBtn) {\n      if (atcBtn.classList.contains('is-disabled')) return\n      if (atcPhase === 'success') {\n        goToCheckout()\n        return\n      }\n      handleAddToCart()\n      return\n    }\n\n    const chip = target.closest('.tbl-base-mini-pdp__chip')\n    if (chip) {\n      chooseDimension(chip.dataset.dimensionName, chip.dataset.dimensionValue)\n    }\n  })\n\n  fullRender()\n\n  return {\n    update(newProps) {\n      console.log('[AMA] Clarity - Customized - update', newProps)\n      const productChanged = newProps.product?.id !== props.product?.id\n      props = { ...newProps, product: injectFakeLengthDimension(newProps.product) }\n      if (productChanged) {\n        fullRender()\n      } else {\n        const variants = props.product?.variants ?? []\n        if (variants.length \u0026\u0026 props.selectedVariant) {\n          dimensions.forEach(dim =\u003e {\n            const v = props.selectedVariant[dim.name]\n            if (v !== undefined \u0026\u0026 v !== null) activated[dim.name] = v\n          })\n          syncActiveChips()\n        }\n        syncVariantContent()\n      }\n    },\n    cleanup() {\n      atcGen += 1\n      cancelAtcResetTimer()\n      el.innerHTML = ''\n    },\n  }\n}\n\nconst seeAllResults = params =\u003e {\n  const query = params.queries?.at(-1) ?? params.rephrasedQuery ?? params.categoryName ?? ''\n  if (!query) return\n  const locale = getLocale()\n  const origin = location.origin\n  const ps = new URLSearchParams()\n  ps.set('q', query)\n  window.location.href = `${origin}/${locale}/search?${ps.toString()}`\n}\n\nconsole.log('[AMA] Clarity - Customized')\nwindow.CLARITY_GLOBAL_CONFIG = {\n  ...(window.CLARITY_GLOBAL_CONFIG || {}),\n  component: {\n    ...(window.CLARITY_GLOBAL_CONFIG?.component || {}),\n    MiniPDP: tblCusotmized,\n  },\n  fn: {\n    ...(window.CLARITY_GLOBAL_CONFIG?.fn || {}),\n    addToCart: tblCusotmizedATC,\n    seeAllResults,\n  },\n}\n","trigger":{"include_pages":[{"type":"any"}],"exclude_pages":null},"_id":"6a1dd2d6dddea736de47fb02"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cstyle\u003e\n/*\n * Self-contained styles for tblCusotmized — combines tblBaseMiniPDP.css\n * (base layout, top bar, hero, dimensions, chips) with the ATC footer\n * additions. Load this file alone; do NOT also load tblBaseMiniPDP.css.\n *\n * The atc-container sits inside the existing scroll area and uses flex: 1\n * to absorb leftover vertical space, anchoring the Add to Cart button to\n * the bottom of the visible scroll viewport. When content is taller than\n * the viewport, the button scrolls into view at the very end.\n */\n\n#cocoaas_chat_wrapper .clarity-mini-pdp--inside-input-container {\n  display: none;\n}\n\n#cocoaas_chat_wrapper .clarity-mini-pdp--inside-container-overlay {\n\theight: 90%;\n}\n\n#tbl-base-mini-pdp-root {\n  position: relative;\n  display: flex;\n  width: 100%;\n  height: 100%;\n  flex-direction: column;\n  align-items: flex-start;\n  gap: 32px;\n  flex-shrink: 0;\n  align-self: stretch;\n}\n\n#tbl-base-mini-pdp-root *,\n#tbl-base-mini-pdp-root *::before,\n#tbl-base-mini-pdp-root *::after {\n  box-sizing: border-box;\n}\n\n#tbl-base-mini-pdp-root button {\n  border: none;\n  padding: 0;\n  margin: 0;\n  cursor: pointer;\n  background: unset;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__top-bar {\n  width: 100%;\n  padding: 32px 16px 0;\n  display: flex;\n  align-items: center;\n  justify-content: flex-start;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__icon-btn {\n  text-transform: uppercase;\n  color: #000;\n  /* Accent/Overline 1 */\n  font-size: var(--typography-font-size-accent-overline-1, 12px);\n  font-style: normal;\n  font-weight: 400;\n  line-height: var(--typography-font-line-height-accent-overline-1, 16px);\n  letter-spacing: var(--typography-font-letter-spacing-accent-overline-1, 0);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__icon-btn svg {\n  display: none;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__scroll {\n  padding: 0 16px 32px;\n  width: 100%;\n  flex: 1;\n  overflow: hidden auto;\n  display: flex;\n  flex-direction: column;\n  gap: 32px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__hero {\n  position: relative;\n  width: 100%;\n  aspect-ratio: 1 / 1;\n  border-radius: var(--border-radius-none, 0);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__hero img {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  object-fit: cover;\n  display: block;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__details {\n  display: flex;\n  flex-direction: column;\n  gap: 32px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__heading {\n  display: flex;\n  flex-direction: column;\n  gap: 20px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__name-block {\n  display: flex;\n  flex-direction: column;\n  gap: 12px;\n  align-items: flex-start;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__title {\n  margin: 0;\n  color: var(--typography-color-default, #2a1e17);\n  /* Title/Title 2/Desktop */\n  font-size: var(--typography-font-size-title-title-2-desktop, 20px);\n  font-style: normal;\n  font-weight: 500;\n  line-height: var(--typography-font-line-height-title-title-2-desktop, 24px);\n  letter-spacing: var(\n    --typography-font-letter-spacing-title-title-2-desktop,\n    0\n  );\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__view {\n  color: var(--typography-color-default, #2a1e17);\n  /* Body/Body Copy 2/Default */\n  font-size: var(--typography-font-size-body-body-2, 14px);\n  font-style: normal;\n  font-weight: 400;\n  line-height: var(--typography-font-line-height-body-body-2, 18px);\n  letter-spacing: var(--typography-font-letter-spacing-body-body-2, 0);\n  text-decoration-line: underline;\n  text-decoration-style: solid;\n  text-decoration-skip-ink: auto;\n  text-decoration-thickness: auto;\n  text-underline-offset: auto;\n  text-underline-position: from-font;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__view[hidden] {\n  display: none;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__price-row {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  /* Body/Body Copy 2/Strong */\n  font-size: var(--typography-font-size-body-body-2, 14px);\n  font-style: normal;\n  font-weight: 500;\n  line-height: var(--typography-font-line-height-body-body-2, 18px);\n  letter-spacing: var(--typography-font-letter-spacing-body-body-2, 0);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__price-row.is-hidden {\n  display: none;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__price {\n  color: var(--typography-color-default, #2a1e17);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__original-price {\n  color: #d51920;\n  font-weight: 500;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__original-price.is-hidden {\n  display: none;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__dimensions {\n  display: flex;\n  flex-direction: column;\n  gap: 32px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__dimension-row {\n  display: flex;\n  flex-direction: column;\n  gap: 12px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__dimension-label {\n  color: var(--typography-color-default, #2a1e17);\n  /* Accent/Overline 1 */\n  font-size: var(--typography-font-size-accent-overline-1, 12px);\n  font-style: normal;\n  font-weight: 400;\n  line-height: var(--typography-font-line-height-accent-overline-1, 16px);\n  letter-spacing: var(--typography-font-letter-spacing-accent-overline-1, 0);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__dimension-label::after {\n  content: \":\";\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__chip-grid {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 8px;\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__chip {\n  text-align: center;\n  flex: 1;\n  padding: 12px 16px;\n  border-radius: var(--border-radius-default, 0);\n  border: 1px solid var(--border-color-light, #e1e1e1);\n  white-space: nowrap;\n  transition: border-color 0.15s;\n  color: var(--typography-color-default, #2a1e17);\n  /* Accent/Overline 1 */\n  font-size: var(--typography-font-size-accent-overline-1, 12px);\n  font-style: normal;\n  font-weight: 400;\n  line-height: var(--typography-font-line-height-accent-overline-1, 16px);\n  letter-spacing: var(--typography-font-letter-spacing-accent-overline-1, 0);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__chip.is-active {\n  border-color: var(--border-color-dark, #2a2a2a);\n}\n\n#tbl-base-mini-pdp-root .tbl-base-mini-pdp__chip.is-disabled {\n  background-color: var(--components-buttons-style-disabled-default, #eee);\n  background-image: linear-gradient(\n    to bottom right,\n    transparent calc(50% - 0.5px),\n    var(--border-color-disabled, #9a9a9a) calc(50% - 0.5px),\n    var(--border-color-disabled, #9a9a9a) calc(50% + 0.5px),\n    transparent calc(50% + 0.5px)\n  );\n  border-color: var(--border-color-disabled, #9a9a9a);\n  color: var(--typography-color-disabled, #707070);\n  cursor: not-allowed;\n}\n\n#tbl-base-mini-pdp-root\n  .tbl-base-mini-pdp__dimension--size\n  .tbl-base-mini-pdp__chip {\n  flex: none;\n  width: 40px;\n  height: 40px;\n  overflow: hidden;\n  padding: 0;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n/* === Customized: Add to Cart footer === */\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-container {\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: flex-end;\n  width: 100%;\n  min-height: 44px;\n}\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-btn {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 100%;\n  height: 44px;\n  background: var(--components-buttons-style-primary-default, #2a1e17);\n  color: var(--components-buttons-style-primary-text, #faf6ec);\n\n  /* Buttons/Buttons 1 */\n  font-size: var(--typography-font-size-buttons-buttons-1, 16px);\n  font-style: normal;\n  font-weight: 500;\n  line-height: var(\n    --typography-font-line-height-buttons-buttons-1,\n    20px\n  ); /* 125% */\n  letter-spacing: var(\n    --typography-font-letter-spacing-buttons-buttons-1,\n    0.24px\n  );\n  cursor: pointer;\n  transition: opacity 0.15s;\n}\n\n/* Cursor reflects any non-clickable state (pending / out of stock / failed).\n   Only fade for `is-disabled` (out of stock / failed); during the pending\n   ATC phase the button stays at full opacity so the red progress bar reads\n   cleanly, but the cursor still signals it can't be clicked again. */\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-btn:disabled,\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-btn.is-disabled {\n  cursor: not-allowed;\n}\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-btn.is-disabled {\n  opacity: 0.5;\n}\n\n/*\n * ATC button: progress-bar fill animation. Layered over the button background\n * during the \"pending\" phase (after the user clicks Add to Cart, before the\n * cart request resolves). The label sits on top via z-index.\n *\n * NOTE: the 1800ms duration must stay in sync with ATC_ANIMATION_MS in\n * tblCusotmized.js — that JS constant gates the parallel setTimeout that\n * waits for the visual fill to finish before showing the result label.\n */\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-btn {\n  position: relative;\n  overflow: hidden;\n}\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-progress {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 0%;\n  background: #896340;\n  z-index: 1;\n  pointer-events: none;\n}\n\n/* Use a CSS animation rather than a transition. A transition would require the\n   `transition: width …` rule to already be on the element's computed style\n   *before* the width changes — toggling a class that adds both the transition\n   rule and the new width in the same recalc lets the browser skip the animation.\n   @keyframes plays unambiguously whenever the class is applied. */\n@keyframes tbl-atc-fill {\n  from { width: 0%; }\n  to { width: 100%; }\n}\n\n#tbl-base-mini-pdp-root\n  .tbl-customized-mini-pdp__atc-progress.is-animating {\n  animation: tbl-atc-fill 1800ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-progress.is-filled {\n  width: 100%;\n}\n\n#tbl-base-mini-pdp-root .tbl-customized-mini-pdp__atc-label {\n  position: relative;\n  z-index: 2;\n}\n\n/* === Customized: ATC top toast === */\n\n/* Toast is anchored to the MiniPDP root (which is position: relative) so it\n   appears inside the MiniPDP panel rather than at the page viewport top. */\n#tbl-base-mini-pdp-root .tbl-customized-toast-container {\n  position: absolute;\n  top: 16px;\n  left: 50%;\n  transform: translateX(-50%);\n  z-index: 10;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  gap: 8px;\n  pointer-events: none;\n}\n\n.tbl-customized-toast {\n  background: #000;\n  color: #fff;\n  border-radius: 8px;\n  padding: 12px 18px;\n  font-size: 14px;\n  font-family: inherit;\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n  opacity: 0;\n  transform: translateY(-12px);\n  transition:\n    opacity 0.2s ease,\n    transform 0.2s ease;\n  pointer-events: auto;\n  min-width: 200px;\n  text-align: center;\n}\n\n.tbl-customized-toast.is-visible {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n\u003c/style\u003e","trigger":{"include_pages":[{"type":"any"}],"exclude_pages":null},"_id":"6a1dd2e3dddea736de47fb0d"},{"uses_overlay":false,"type":"js","parametrized_definition":"const pdpWeblayerId = \"6a1f4cfcc3ab7ea905286f91\";\nconst searchWeblayerId = \"6a1dd8f68183ab26f544e838\";\n\nconst loadClarityUtils = async () =\u003e {\n  const url = 'https://unpkg.com/@bloomreach/clarity-utils@1.0.8/dist/index.global.js'\n  for (let attempt = 1; attempt \u003c= 5; attempt++) {\n    try {\n      await new Promise((resolve, reject) =\u003e {\n        const s = document.createElement('script')\n        s.src = url\n        s.onload = resolve\n        s.onerror = () =\u003e reject(new Error(`Failed to load ${url}`))\n        document.head.appendChild(s)\n      })\n      return\n    } catch (err) {\n      console.warn(`clarity-utils load attempt ${attempt}/5 failed`, err)\n      if (attempt === 5) throw err\n      await new Promise(r =\u003e setTimeout(r, 200 * attempt))\n    }\n  }\n}\n\nconst clarityUtilsLoaded = loadClarityUtils()\n\nwindow.CLARITY_HELPER = {\n\t...(window.CLARITY_HELPER || {}),\n\tinvokePDP: () =\u003e {\n\t  window.CLARITY.setSource(pdpWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n\t},\n    invokeSearchHubOrch: input =\u003e {\n\t  window.CLARITY.setSource(searchWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n      window.CLARITY.call('user_send_message', {\n        input,\n        type: 'text',\n        force: true,\n        source: 'DEFAULT',\n      });\n\t},\n\tisSearch: async (input, config) =\u003e {\n\t  if (!input?.trim()) return;\n\t  console.log('clarity is search', input, config)\n\t  await clarityUtilsLoaded\n\t  const result = window.clarityUtils.isSearch(input, { mode: 'score', ...(config ?? {}) })\n\t  const logger = window.brweb ?? window.exponea\n\t  logger.track('clarity', {\n\t  \taction: 'search_orchestrator',\n\t  \tsearch_string: input,\n\t  \tis_conversational: !result\n\t  });\n\t  return result;\n\t},\n}","trigger":{"include_pages":[{"url":"/en-ca","type":"contains"}],"exclude_pages":null},"_id":"6a1dd8f68183ab26f544e842"},{"uses_overlay":false,"type":"js","parametrized_definition":"const pdpWeblayerId = \"6a1f4d8a740d1b8e60499f43\";\nconst searchWeblayerId = \"6a1dda88d538b7cc809b89a8\";\n\nconst loadClarityUtils = async () =\u003e {\n  const url = 'https://unpkg.com/@bloomreach/clarity-utils@1.0.8/dist/index.global.js'\n  for (let attempt = 1; attempt \u003c= 5; attempt++) {\n    try {\n      await new Promise((resolve, reject) =\u003e {\n        const s = document.createElement('script')\n        s.src = url\n        s.onload = resolve\n        s.onerror = () =\u003e reject(new Error(`Failed to load ${url}`))\n        document.head.appendChild(s)\n      })\n      return\n    } catch (err) {\n      console.warn(`clarity-utils load attempt ${attempt}/5 failed`, err)\n      if (attempt === 5) throw err\n      await new Promise(r =\u003e setTimeout(r, 200 * attempt))\n    }\n  }\n}\n\nconst clarityUtilsLoaded = loadClarityUtils()\n\nwindow.CLARITY_HELPER = {\n\t...(window.CLARITY_HELPER || {}),\n\tinvokePDP: () =\u003e {\n\t  window.CLARITY.setSource(pdpWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n\t},\n    invokeSearchHubOrch: input =\u003e {\n\t  window.CLARITY.setSource(searchWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n      window.CLARITY.call('user_send_message', {\n        input,\n        type: 'text',\n        force: true,\n        source: 'DEFAULT',\n      });\n\t},\n\tisSearch: async (input, config) =\u003e {\n\t  if (!input?.trim()) return;\n\t  console.log('clarity is search', input, config)\n\t  await clarityUtilsLoaded\n\t  const result = window.clarityUtils.isSearch(input, { mode: 'score', ...(config ?? {}) })\n\t  const logger = window.brweb ?? window.exponea\n\t  logger.track('clarity', {\n\t  \taction: 'search_orchestrator',\n\t  \tsearch_string: input,\n\t  \tis_conversational: !result\n\t  });\n\t  return result;\n\t},\n}","trigger":{"include_pages":[{"url":"/fr-ca","type":"contains"}],"exclude_pages":null},"_id":"6a1dda88d538b7cc809b89b2"},{"uses_overlay":false,"type":"js","parametrized_definition":"const pdpWeblayerId = \"6a1f4c37c3ab7ea905286f7e\";\nconst searchWeblayerId = \"6a1deacf8183ab26f544edea\";\n\nconst loadClarityUtils = async () =\u003e {\n  const url = 'https://unpkg.com/@bloomreach/clarity-utils@1.0.8/dist/index.global.js'\n  for (let attempt = 1; attempt \u003c= 5; attempt++) {\n    try {\n      await new Promise((resolve, reject) =\u003e {\n        const s = document.createElement('script')\n        s.src = url\n        s.onload = resolve\n        s.onerror = () =\u003e reject(new Error(`Failed to load ${url}`))\n        document.head.appendChild(s)\n      })\n      return\n    } catch (err) {\n      console.warn(`clarity-utils load attempt ${attempt}/5 failed`, err)\n      if (attempt === 5) throw err\n      await new Promise(r =\u003e setTimeout(r, 200 * attempt))\n    }\n  }\n}\n\nconst clarityUtilsLoaded = loadClarityUtils()\n\nwindow.CLARITY_HELPER = {\n\t...(window.CLARITY_HELPER || {}),\n\tinvokePDP: () =\u003e {\n\t  window.CLARITY.setSource(pdpWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n\t},\n    invokeSearchHubOrch: input =\u003e {\n\t  window.CLARITY.setSource(searchWeblayerId);\n      window.CLARITY.call('show_badge');\n      window.CLARITY.call('open_chat');\n      window.CLARITY.call('user_send_message', {\n        input,\n        type: 'text',\n        force: true,\n        source: 'DEFAULT',\n      });\n\t},\n\tisSearch: async (input, config) =\u003e {\n\t  if (!input?.trim()) return;\n\t  console.log('clarity is search', input, config)\n\t  await clarityUtilsLoaded\n\t  const result = window.clarityUtils.isSearch(input, { mode: 'score', ...(config ?? {}) })\n\t  const logger = window.brweb ?? window.exponea\n\t  logger.track('clarity', {\n\t  \taction: 'search_orchestrator',\n\t  \tsearch_string: input,\n\t  \tis_conversational: !result\n\t  });\n\t  return result;\n\t},\n}","trigger":{"include_pages":[{"url":"/es-us","type":"contains"}],"exclude_pages":null},"_id":"6a1dead08183ab26f544edf4"}],"vars":{"data":[]}}