{
  "version": 3,
  "sources": ["/cdn/shop/t/4/assets/utilities.js?bust=1781428692707"],
  "sourcesContent": ["/**\n * Request an idle callback or fallback to setTimeout\n * @returns {function} The requestIdleCallback function\n */\nexport const requestIdleCallback =\n  typeof window.requestIdleCallback == 'function' ? window.requestIdleCallback : setTimeout;\n\n/**\n * Returns a promise that resolves after yielding to the main thread.\n * @see https://web.dev/articles/optimize-long-tasks#scheduler-yield\n */\nexport const yieldToMainThread = () => {\n  if ('yield' in scheduler) {\n    // @ts-ignore - TypeScript doesn't recognize the yield method yet.\n    return scheduler.yield();\n  }\n\n  return new Promise((resolve) => {\n    requestAnimationFrame(() => {\n      setTimeout(resolve, 0);\n    });\n  });\n};\n\n/**\n * Tells if we are on a low power device based on the number of CPU cores and RAM\n * @returns {boolean} True if the device is a low power device, false otherwise\n */\nexport function isLowPowerDevice() {\n  return Number(navigator.hardwareConcurrency) <= 2 || Number(navigator.deviceMemory) <= 2;\n}\n\n/**\n * Check if the browser supports View Transitions API\n * @returns {boolean} True if the browser supports View Transitions API, false otherwise\n */\nexport function supportsViewTransitions() {\n  return typeof document.startViewTransition === 'function';\n}\n\n/**\n * The current view transition\n * @type {{ current: Promise<void> | undefined }}\n */\nexport const viewTransition = {\n  current: undefined,\n};\n\n/**\n * Functions to run when a view transition of a given type is started\n * @type {{ [key: string]: () => Promise<(() => void) | undefined> }}\n */\nconst viewTransitionTypes = {\n  'product-grid': async () => {\n    const grid = document.querySelector('.product-grid');\n    const productCards = /** @type {HTMLElement[]} */ ([\n      ...document.querySelectorAll('.product-grid .product-grid__item'),\n    ]);\n\n    if (!grid || !productCards.length) return;\n\n    await new Promise((resolve) =>\n      requestIdleCallback(() => {\n        const cardsToAnimate = getCardsToAnimate(grid, productCards);\n\n        productCards.forEach((card, index) => {\n          if (index < cardsToAnimate) {\n            card.style.setProperty('view-transition-name', `product-card-${card.dataset.productId}`);\n          } else {\n            card.style.setProperty('content-visibility', 'hidden');\n          }\n        });\n\n        resolve(null);\n      })\n    );\n\n    return () =>\n      productCards.forEach((card) => {\n        card.style.removeProperty('view-transition-name');\n        card.style.removeProperty('content-visibility');\n      });\n  },\n};\n\n/**\n * Starts a view transition\n * @param {() => void} callback The callback to call when the view transition starts\n * @param {string[]} [types] The types of view transition to use\n * @returns {Promise<void>} A promise that resolves when the view transition finishes\n */\nexport function startViewTransition(callback, types) {\n  // Check if the API is supported and transitions are desired\n  if (!supportsViewTransitions() || isLowPowerDevice() || prefersReducedMotion()) {\n    callback();\n    return Promise.resolve();\n  }\n\n  // eslint-disable-next-line no-async-promise-executor\n  return new Promise(async (resolve) => {\n    let cleanupFunctions = [];\n\n    if (types) {\n      for (const type of types) {\n        if (viewTransitionTypes[type]) {\n          const cleanupFunction = await viewTransitionTypes[type]();\n          if (cleanupFunction) cleanupFunctions.push(cleanupFunction);\n        }\n      }\n    }\n\n    const transition = document.startViewTransition(callback);\n\n    if (!viewTransition.current) {\n      viewTransition.current = transition.finished;\n    }\n\n    if (types) types.forEach((type) => transition.types.add(type));\n\n    transition.finished.then(() => {\n      viewTransition.current = undefined;\n      cleanupFunctions.forEach((cleanupFunction) => cleanupFunction());\n      resolve();\n    });\n  });\n}\n\n/**\n * @typedef {{ [key: string]: string | undefined }} Headers\n */\n\n/**\n * @typedef {Object} FetchConfig\n * @property {string} method\n * @property {Headers} headers\n * @property {string | FormData | undefined} [body]\n */\n\n/**\n * Creates a fetch configuration object\n * @param {string} [type] The type of response to expect\n * @param {Object} [config] The config of the request\n * @param {FetchConfig['body']} [config.body] The body of the request\n * @param {FetchConfig['headers']} [config.headers] The headers of the request\n * @returns {RequestInit} The fetch configuration object\n */\nexport function fetchConfig(type = 'json', config = {}) {\n  /** @type {Headers} */\n  const headers = { 'Content-Type': 'application/json', Accept: `application/${type}`, ...config.headers };\n\n  if (type === 'javascript') {\n    headers['X-Requested-With'] = 'XMLHttpRequest';\n    delete headers['Content-Type'];\n  }\n\n  return {\n    method: 'POST',\n    headers: /** @type {HeadersInit} */ (headers),\n    body: config.body,\n  };\n}\n\n/**\n * Creates a debounced function that delays calling the provided function (fn)\n * until after wait milliseconds have elapsed since the last time\n * the debounced function was invoked. The returned function has a .cancel()\n * method to cancel any pending calls.\n *\n * @template {(...args: any[]) => any} T\n * @param {T} fn The function to debounce\n * @param {number} wait The time (in milliseconds) to wait before calling fn\n * @returns {T & { cancel(): void }} A debounced version of fn with a .cancel() method\n */\nexport function debounce(fn, wait) {\n  /** @type {number | undefined} */\n  let timeout;\n\n  /** @param {...any} args */\n  function debounced(...args) {\n    clearTimeout(timeout);\n    timeout = setTimeout(() => fn.apply(this, args), wait);\n  }\n\n  // Add the .cancel method:\n  debounced.cancel = () => {\n    clearTimeout(timeout);\n  };\n\n  return /** @type {T & { cancel(): void }} */ (debounced);\n}\n\n/**\n * Creates a throttled function that calls the provided function (fn) at most once per every wait milliseconds\n *\n * @template {(...args: any[]) => any} T\n * @param {T} fn The function to throttle\n * @param {number} delay The time (in milliseconds) to wait before calling fn\n * @returns {T & { cancel(): void }} A throttled version of fn with a .cancel() method\n */\nexport function throttle(fn, delay) {\n  let lastCall = 0;\n\n  /** @param {...any} args */\n  function throttled(...args) {\n    const now = performance.now();\n    // If the time since the last call exceeds the delay, execute the callback\n    if (now - lastCall >= delay) {\n      lastCall = now;\n      fn.apply(this, args);\n    }\n  }\n\n  throttled.cancel = () => {\n    lastCall = performance.now();\n  };\n\n  return /** @type {T & { cancel(): void }} */ (throttled);\n}\n\n/**\n * A media query for reduced motion\n * @type {MediaQueryList}\n */\nconst reducedMotion = matchMedia('(prefers-reduced-motion: reduce)');\n\n/**\n * Check if the user prefers reduced motion\n * @returns {boolean} True if the user prefers reduced motion, false otherwise\n */\nexport function prefersReducedMotion() {\n  return reducedMotion.matches;\n}\n\n/**\n * Normalize a string\n * @param {string} str The string to normalize\n * @returns {string} The normalized string\n */\nexport function normalizeString(str) {\n  return str\n    .normalize('NFD')\n    .replace(/\\p{Diacritic}/gu, '')\n    .toLowerCase();\n}\n\n/**\n * Check if the document is ready/loaded and call the callback when it is.\n * @param {() => void} callback The function to call when the document is ready.\n */\nexport function onDocumentLoaded(callback) {\n  if (document.readyState === 'complete') {\n    callback();\n  } else {\n    window.addEventListener('load', callback);\n  }\n}\n\n/**\n * Check if the DOM is ready and call the callback when it is.\n * This fires when the DOM is fully parsed but before all resources are loaded.\n * @param {() => void} callback The function to call when the DOM is ready.\n */\nexport function onDocumentReady(callback) {\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', callback);\n  } else {\n    callback();\n  }\n}\n\n/**\n * Removes will-change from an element after an animation ends.\n * Intended to be used as an animationend event listener.\n * @param {AnimationEvent} event The animation event.\n */\nexport function removeWillChangeOnAnimationEnd(event) {\n  const target = event.target;\n  if (target && target instanceof HTMLElement) {\n    target.style.setProperty('will-change', 'unset');\n    target.removeEventListener('animationend', removeWillChangeOnAnimationEnd);\n  }\n}\n\n/**\n * Wait for all animations to finish before calling the callback.\n * @param {Element | Element[]} elements The element(s) whose animations to wait for.\n * @param {() => void} [callback] The function to call when all animations are finished.\n * @param {Object} [options] The options to pass to `Element.getAnimations`.\n * @returns {Promise<void>} A promise that resolves when all animations are finished.\n */\nexport function onAnimationEnd(elements, callback, options = { subtree: true }) {\n  const animations = Array.isArray(elements)\n    ? elements.flatMap((element) => element.getAnimations(options))\n    : elements.getAnimations(options);\n  const animationPromises = animations.reduce((acc, animation) => {\n    // Ignore ViewTimeline animations\n    if (animation.timeline instanceof DocumentTimeline) {\n      acc.push(animation.finished);\n    }\n\n    return acc;\n  }, /** @type {Promise<Animation>[]} */ ([]));\n\n  return Promise.allSettled(animationPromises).then(callback);\n}\n\n/**\n * Check if the click is outside the element.\n * @param {MouseEvent} event The mouse event.\n * @param {Element} element The element to check.\n * @returns {boolean} True if the click is outside the element, false otherwise.\n */\nexport function isClickedOutside(event, element) {\n  if (event.target instanceof HTMLDialogElement || !(event.target instanceof Element)) {\n    return !isPointWithinElement(event.clientX, event.clientY, element);\n  }\n\n  return !element.contains(event.target);\n}\n\n/**\n * Check if a point is within an element.\n * @param {number} x The x coordinate of the point.\n * @param {number} y The y coordinate of the point.\n * @param {Element} element The element to check.\n * @returns {boolean} True if the point is within the element, false otherwise.\n */\nexport function isPointWithinElement(x, y, element) {\n  const { left, right, top, bottom } = element.getBoundingClientRect();\n\n  return x >= left && x <= right && y >= top && y <= bottom;\n}\n\n/**\n * A media query for large screens\n * @type {MediaQueryList}\n */\nexport const mediaQueryLarge = matchMedia('(min-width: 750px)');\n\n/**\n * Check if the current breakpoint is mobile\n * @returns {boolean} True if the current breakpoint is mobile, false otherwise\n */\nexport function isMobileBreakpoint() {\n  return !mediaQueryLarge.matches;\n}\n\n/**\n * Check if the current breakpoint is desktop\n * @returns {boolean} True if the current breakpoint is desktop, false otherwise\n */\nexport function isDesktopBreakpoint() {\n  return mediaQueryLarge.matches;\n}\n\n/**\n * Check if the device is a touch device independently ot the screen size\n * @returns {boolean} True if the device is a touch device, false otherwise\n */\nexport function isTouchDevice() {\n  return 'ontouchstart' in window && navigator.maxTouchPoints > 0;\n}\n\n/**\n * Clamps a number between a minimum and maximum value.\n * @param {number} value - The input number to clamp.\n * @param {number} min - The minimum value.\n * @param {number} max - The maximum value.\n * @returns {number} The clamped value.\n */\nexport function clamp(value, min, max) {\n  return Math.max(min, Math.min(value, max));\n}\n\n/**\n * Calculates the center point of an element along the specified axis.\n * @param {Element} element - The DOM element to find the center of.\n * @param {'x' | 'y'} [axis] - The axis ('x' or 'y') to get the center for. If not provided, returns both axes.\n * @template {('x' | 'y')} T\n * @param {T} [axis]\n * @returns {T extends ('x' | 'y') ? number : {x: number, y: number}} The center point along the axis or an object with x and y coordinates.\n */\nexport function center(element, axis) {\n  const { left, width, top, height } = element.getBoundingClientRect();\n  const point = {\n    x: left + width / 2,\n    y: top + height / 2,\n  };\n\n  if (axis) return /**  @type {any} */ (point[axis]);\n\n  return /**  @type {any} */ (point);\n}\n\n/**\n * Calculates the start point of an element along the specified axis.\n * @param {Element} element - The DOM element to find the start of.\n * @param {'x' | 'y'} [axis] - The axis ('x' or 'y') to get the start for. If not provided, returns both axes.\n * @returns {number | {x: number, y: number}} The start point along the axis or an object with x and y coordinates.\n */\nexport function start(element, axis) {\n  const { left, top } = element.getBoundingClientRect();\n  const point = { x: left, y: top };\n\n  if (axis) return /**  @type {any} */ (point[axis]);\n\n  return /**  @type {any} */ (point);\n}\n\n/**\n * Finds the value in an array that is closest to a target value.\n * @param {number[]} values - An array of numbers.\n * @param {number} target - The target number to find the closest value to.\n * @returns {number} The value from the array closest to the target.\n */\nexport function closest(values, target) {\n  return values.reduce(function (prev, curr) {\n    return Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev;\n  });\n}\n\n/**\n * Prevents the default action of an event.\n * @param {Event} event - The event to prevent the default action of.\n */\nexport function preventDefault(event) {\n  event.preventDefault();\n}\n\n/**\n * Get the visible elements within a root element.\n * @template {Element} T\n * @param {Element} root - The element within which elements should be visible.\n * @param {T[] | undefined} elements - The elements to check for visibility.\n * @param {number} [ratio=1] - The minimum percentage of the element that must be visible.\n * @param {'x' | 'y'} [axis] - Whether to only check along 'x' axis, 'y' axis, or both if undefined.\n * @returns {T[]} An array containing the visible elements.\n */\nexport function getVisibleElements(root, elements, ratio = 1, axis) {\n  if (!elements?.length) return [];\n  const rootRect = root.getBoundingClientRect();\n\n  return elements.filter((element) => {\n    const { width, height, top, right, left, bottom } = element.getBoundingClientRect();\n\n    if (ratio < 1) {\n      const intersectionLeft = Math.max(rootRect.left, left);\n      const intersectionRight = Math.min(rootRect.right, right);\n      const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);\n\n      if (axis === 'x') {\n        return width > 0 && intersectionWidth / width >= ratio;\n      }\n\n      const intersectionTop = Math.max(rootRect.top, top);\n      const intersectionBottom = Math.min(rootRect.bottom, bottom);\n      const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);\n\n      if (axis === 'y') {\n        return height > 0 && intersectionHeight / height >= ratio;\n      }\n\n      const intersectionArea = intersectionWidth * intersectionHeight;\n      const elementArea = width * height;\n\n      // Check that at least the specified ratio of the element is visible\n      return elementArea > 0 && intersectionArea / elementArea >= ratio;\n    }\n\n    const isWithinX = left >= rootRect.left && right <= rootRect.right;\n    if (axis === 'x') {\n      return isWithinX;\n    }\n\n    const isWithinY = top >= rootRect.top && bottom <= rootRect.bottom;\n    if (axis === 'y') {\n      return isWithinY;\n    }\n\n    return isWithinX && isWithinY;\n  });\n}\n\nexport function getIOSVersion() {\n  const { userAgent } = navigator;\n  const isIOS = /(iPhone|iPad)/i.test(userAgent);\n\n  if (!isIOS) return null;\n\n  const version = userAgent.match(/OS ([\\d_]+)/)?.[1];\n  const [major, minor] = version?.split('_') || [];\n  if (!version || !major) return null;\n\n  return {\n    fullString: version.replace('_', '.'),\n    major: parseInt(major, 10),\n    minor: minor ? parseInt(minor, 10) : 0,\n  };\n}\n\n/**\n * Determines which grid items should be animated during a transition.\n * It makes an estimation based on the zoom-out card size because it's\n * the common denominator for both transition states. I.e. transitioning either\n * from 10 to 20 cards the other way around, both need 20 cards to be animated.\n * @param {Element} grid - The grid element\n * @param {Element[]} cards - The cards to animate\n * @returns {number} - Number of cards that should be animated\n */\nfunction getCardsToAnimate(grid, cards) {\n  if (!grid || !cards || cards.length === 0) return 0;\n\n  const itemSample = cards[0];\n  if (!itemSample) return 0;\n\n  // Calculate the visible area of the grid for the Y axis. Assume X is always fully visible:\n  const gridRect = grid.getBoundingClientRect();\n  const visibleArea = {\n    top: Math.max(0, gridRect.top),\n    bottom: Math.min(window.innerHeight, gridRect.bottom),\n  };\n\n  const visibleHeight = Math.round(visibleArea.bottom - visibleArea.top);\n  if (visibleHeight <= 0) return 0;\n\n  /** @type {import('product-card').ProductCard | null} */\n  const cardSample = itemSample.querySelector('product-card');\n  const gridStyle = getComputedStyle(grid);\n\n  const galleryAspectRatio = cardSample?.refs?.cardGallery?.style.getPropertyValue('--gallery-aspect-ratio') || '';\n  let aspectRatio = parseFloat(galleryAspectRatio) || 0.5;\n  if (galleryAspectRatio?.includes('/')) {\n    const [width = '1', height = '2'] = galleryAspectRatio.split('/');\n    aspectRatio = parseInt(width, 10) / parseInt(height, 10);\n  }\n\n  const cardGap = parseInt(cardSample?.refs?.productCardLink?.style.getPropertyValue('--product-card-gap') || '') || 12;\n  const gridGap = parseInt(gridStyle.getPropertyValue('--product-grid-gap')) || 12;\n\n  // Assume only a couple of lines of text in the card details (title and price).\n  // If the title wraps into more lines, we might just animate more cards, but that's fine.\n  const detailsSize = ((parseInt(gridStyle.fontSize) || 16) + 2) * 2;\n\n  const isMobile = window.innerWidth < 750;\n\n  // Always use the zoom-out state card width\n  const cardWidth = isMobile ? Math.round((gridRect.width - gridGap) / 2) : 100;\n  const cardHeight = Math.round(cardWidth / aspectRatio) + cardGap + detailsSize;\n\n  // Calculate the number of cards that fit in the visible area:\n  // - The width estimation is pretty accurate, we can ignore decimals.\n  // - The height estimation needs to account for peeking rows, so we round up.\n  const columnsInGrid = isMobile ? 2 : Math.floor((gridRect.width + gridGap) / (cardWidth + gridGap));\n  const rowsInGrid = Math.ceil((visibleHeight - gridGap) / (cardHeight + gridGap));\n\n  return columnsInGrid * rowsInGrid;\n}\n\n/**\n * Preloads an image\n * @param {string} src - The source of the image to preload\n */\nexport function preloadImage(src) {\n  const image = new Image();\n  image.src = src;\n}\n\nexport class TextComponent extends HTMLElement {\n  shimmer() {\n    this.setAttribute('shimmer', '');\n  }\n}\n\nif (!customElements.get('text-component')) {\n  customElements.define('text-component', TextComponent);\n}\n\n/**\n * Resets the shimmer attribute on all elements in the container.\n * @param {Element} [container] - The container to reset the shimmer attribute on.\n */\nexport function resetShimmer(container = document.body) {\n  const shimmer = container.querySelectorAll('[shimmer]');\n  shimmer.forEach((item) => item.removeAttribute('shimmer'));\n}\n\n/**\n * Change the meta theme color of the browser.\n * @param {string} color - The color value (e.g., 'rgb(255, 255, 255)')\n */\nexport function changeMetaThemeColor(color) {\n  const metaThemeColor = document.head.querySelector('meta[name=\"theme-color\"]');\n  if (metaThemeColor && color) {\n    metaThemeColor.setAttribute('content', color);\n  }\n}\n\n/**\n * Gets the `view` URL search parameter value, if it exists.\n * Useful for Section Rendering API calls to get HTML markup for the correct template view.\n * Primarily used in testing alternative template views.\n * @returns {string | null} The view parameter value, or null if it doesn't exist\n */\nexport function getViewParameterValue() {\n  return new URLSearchParams(window.location.search).get('view');\n}\n\n/**\n * Helper to parse integer with a default fallback\n * Handles the case where 0 is a valid value (not falsy)\n * @template {number|null} T\n * @param {string|number|null|undefined} value - The value to parse\n * @param {T} defaultValue - The default value (number or null)\n * @returns {number|T} The parsed integer or default value\n */\nexport function parseIntOrDefault(value, defaultValue) {\n  if (value === null || value === undefined || value === '') {\n    return defaultValue;\n  }\n  const parsed = parseInt(value.toString());\n  return isNaN(parsed) ? defaultValue : parsed;\n}\n\nclass Scheduler {\n  /** @type {Set<() => void>} */\n  #queue = new Set();\n  /** @type {boolean} */\n  #scheduled = false;\n\n  /** @param {() => void} task */\n  schedule = async (task) => {\n    this.#queue.add(task);\n\n    if (!this.#scheduled) {\n      this.#scheduled = true;\n\n      // Wait for any in-progress view transitions to finish\n      if (viewTransition.current) await viewTransition.current;\n\n      requestAnimationFrame(this.flush);\n    }\n  };\n\n  flush = () => {\n    for (const task of this.#queue) {\n      setTimeout(task, 0);\n    }\n\n    this.#queue.clear();\n    this.#scheduled = false;\n  };\n}\n\nexport const scheduler = new Scheduler();\n\n/**\n * Executes a callback once per session when in the Shopify theme editor\n * @param {HTMLElement} element - The element to check for the shopify editor block id\n * @param {string} sessionKeyName - Unique key for the session storage\n * @param {() => void} callback - Function to execute\n * @returns {void} - Void if the callback was executed, undefined if it wasn't\n */\nexport function oncePerEditorSession(element, sessionKeyName, callback) {\n  const isInThemeEditor = window.Shopify?.designMode;\n  const shopifyEditorSectionId = JSON.parse(element.dataset.shopifyEditorSection || '{}').id;\n  const shopifyEditorBlockId = JSON.parse(element.dataset.shopifyEditorBlock || '{}').id;\n  const editorId = shopifyEditorSectionId || shopifyEditorBlockId;\n  const uniqueSessionKey = `${sessionKeyName}-${editorId}`;\n\n  if (isInThemeEditor && sessionStorage.getItem(uniqueSessionKey)) return;\n\n  callback();\n\n  if (isInThemeEditor) sessionStorage.setItem(uniqueSessionKey, 'true');\n\n  return;\n}\n\n/**\n * A custom ResizeObserver that only calls the callback when the element is resized.\n * By default the ResizeObserver callback is called when the element is first observed.\n */\nexport class ResizeNotifier extends ResizeObserver {\n  #initialized = false;\n\n  /**\n   * @param {ResizeObserverCallback} callback\n   */\n  constructor(callback) {\n    super((entries) => {\n      if (this.#initialized) return callback(entries, this);\n      this.#initialized = true;\n    });\n  }\n\n  disconnect() {\n    this.#initialized = false;\n    super.disconnect();\n  }\n}\n\n/**\n * Sets the menuStyle dataset attribute on the header component element.\n */\nexport function setHeaderMenuStyle() {\n  const headerComponent = /** @type {HTMLElement} | null */ (document.querySelector('#header-component'));\n  if (headerComponent) {\n    window.requestAnimationFrame(() => {\n      const overflowList = headerComponent?.querySelector('overflow-list');\n      const hasReachedMinimum = overflowList && overflowList.hasAttribute('minimum-reached');\n      headerComponent.dataset.menuStyle = isTouchDevice() || hasReachedMinimum ? 'drawer' : 'menu';\n    });\n  }\n}\n\n/**\n * Header group includes the header (with the menu, etc) and other sections like announcements, dividers, etc.\n * @param {HTMLElement | null} header - The header element\n * @param {HTMLElement | null} headerGroup - The header group element, defaults to the #header-group element\n * @returns {number} The height of the header group\n */\nexport function calculateHeaderGroupHeight(\n  header = document.querySelector('#header-component'),\n  headerGroup = document.querySelector('#header-group')\n) {\n  if (!headerGroup) return 0;\n\n  let totalHeight = 0;\n  const children = headerGroup.children;\n  for (let i = 0; i < children.length; i++) {\n    const element = children[i];\n    if (element === header || !(element instanceof HTMLElement)) continue;\n    totalHeight += element.offsetHeight;\n  }\n\n  // If the header is transparent and has a sibling section, add the height of the header to the total height\n  if (header instanceof HTMLElement && header.hasAttribute('transparent') && header.parentElement?.nextElementSibling) {\n    return totalHeight + header.offsetHeight;\n  }\n\n  return totalHeight;\n}\n\n/**\n * Updates CSS custom properties for transparent header offset calculation\n * Avoids expensive :has() selectors\n */\nfunction updateTransparentHeaderOffset() {\n  const header = document.querySelector('#header-component');\n  const headerGroup = document.querySelector('#header-group');\n  const hasHeaderSection = headerGroup?.querySelector('.header-section');\n  if (!hasHeaderSection || !header?.hasAttribute('transparent')) {\n    document.body.style.setProperty('--transparent-header-offset-boolean', '0');\n    return;\n  }\n\n  const hasImmediateSection = hasHeaderSection.nextElementSibling?.classList.contains('shopify-section');\n\n  const shouldApplyOffset = !hasImmediateSection ? '1' : '0';\n  document.body.style.setProperty('--transparent-header-offset-boolean', shouldApplyOffset);\n}\n\n/**\n * Initialize and maintain header height CSS variables.\n */\nfunction updateHeaderHeights() {\n  const header = document.querySelector('header-component');\n\n  // Early exit if no header - nothing to do\n  if (!(header instanceof HTMLElement)) return;\n\n  // Calculate initial heights\n  const headerHeight = header.offsetHeight;\n  const headerGroupHeight = calculateHeaderGroupHeight(header);\n  const headerTopRow = /** @type {HTMLElement} | null */ (header.querySelector('.header__row--top'));\n\n  document.body.style.setProperty('--header-height', `${headerHeight}px`);\n  document.body.style.setProperty('--header-group-height', `${headerGroupHeight}px`);\n\n  if (headerTopRow) {\n    window.requestAnimationFrame(function () {\n      header.style.setProperty('--top-row-height', `${headerTopRow.offsetHeight}px`);\n    });\n  }\n}\n\nexport function updateAllHeaderCustomProperties() {\n  updateHeaderHeights();\n  updateTransparentHeaderOffset();\n  setHeaderMenuStyle();\n}\n\n// Theme is not defined in some layouts, like the gift card page\nif (typeof Theme !== 'undefined') {\n  Theme.utilities = {\n    ...Theme.utilities,\n    scheduler: scheduler,\n  };\n}\n\nconst storyEditionSectionId = 'template--20410372423782__raven_astrid_home_v2';\n\nasync function refreshCachedRavenAstridHomepage() {\n  if (window.location.pathname !== '/') return;\n\n  const currentSection = document.querySelector('[id*=\"__raven_astrid_home\"]');\n  const currentHeadline = currentSection?.querySelector('.sales-hero h1')?.textContent?.trim();\n\n  if (\n    !(currentSection instanceof HTMLElement) ||\n    currentHeadline === 'Some People Hear Music. Others Hear the Call.'\n  ) {\n    return;\n  }\n\n  try {\n    const response = await fetch(\n      `/?sections=${encodeURIComponent(storyEditionSectionId)}&ra_revision=story-led-editions-v2`,\n      { cache: 'no-store', headers: { Accept: 'application/json' } }\n    );\n    if (!response.ok) return;\n\n    const sections = await response.json();\n    const sectionHtml = sections[storyEditionSectionId];\n    if (!sectionHtml) return;\n\n    const template = document.createElement('template');\n    template.innerHTML = sectionHtml.trim();\n    const nextSection = template.content.firstElementChild;\n    if (!(nextSection instanceof HTMLElement)) return;\n\n    currentSection.replaceWith(nextSection);\n  } catch {\n    // Leave the server-rendered page intact if Shopify's Section API is unavailable.\n  }\n}\n\nif (document.readyState === 'loading') {\n  document.addEventListener('DOMContentLoaded', refreshCachedRavenAstridHomepage, { once: true });\n} else {\n  refreshCachedRavenAstridHomepage();\n}\n"],
  "mappings": "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",
  "names": []
}
