{
  "version": 3,
  "sources": ["../components/timer.js", "../components/TabbedNavigator.js", "../components/site-nav.js", "../components/scroll-to-top.js", "../components/combobox/listbox.js", "../components/secondary-nav.js", "../components/wx-loader.js", "../locationSearch.js", "../components/combobox/combobox.js", "../components/recent-locations.js", "../components/combobox/location-listbox.js", "../components/saved-locations.js", "../components/saved-locations-section.js", "../aws-rum.js", "../components/offline-banner.js", "../components/aria-live.js", "../components/Accordion.js", "../components/Tabs.js", "../components/county-alert-daily-alert-handler.js", "../components/map.js", "../components/alertMap.js", "../components/geobuf.js", "../components/util.js", "../components/countyAlertMap.js", "../radar.js"],
  "sourcesContent": ["/** Convenience class for using setTimeout. */\nexport default class Timer {\n  constructor() {\n    this.timer = this.callback = this.delay = null;\n  }\n\n  stop = () => {\n    if (this.timer === null) return;\n    clearTimeout(this.timer);\n    this.timer = this.callback = this.delay = null;\n  };\n\n  start = (callback, delay) => {\n    this.stop();\n    this.callback = callback;\n    this.delay = Number.isFinite(delay) ? delay : 2000;\n    this.timer = setTimeout(callback, this.delay);\n  };\n\n  reset = () => {\n    if (this.timer === null) return;\n    this.start(this.callback, this.delay);\n  };\n}\n", "class TabbedNavigator extends HTMLElement {\n  constructor() {\n    super();\n\n    // Bind this context to methods that need it\n    this.handleAlertAnchorClick = this.handleAlertAnchorClick.bind(this);\n    this.handleDescendantClick = this.handleDescendantClick.bind(this);\n    this.handleTabButtonClick = this.handleTabButtonClick.bind(this);\n    this.handlePopState = this.handlePopState.bind(this);\n    this.switchToTab = this.switchToTab.bind(this);\n    this.scrollToAccordion = this.scrollToAccordion.bind(this);\n    this.navigateAlertAnchor = this.navigateAlertAnchor.bind(this);\n    this.updateTabScrollState = this.updateTabScrollState.bind(this);\n  }\n\n  connectedCallback() {\n    const pointTablist = this.querySelector(\"#point-page-tablist\");\n    if (pointTablist) {\n      // Capture scroll events because they do not bubble.\n      this.addEventListener(\"scroll\", this.updateTabScrollState, true);\n      this.tablistResizeObserver = new ResizeObserver(\n        this.updateTabScrollState,\n      );\n      this.tablistResizeObserver.observe(this);\n      this.tablistResizeObserver.observe(pointTablist);\n      pointTablist.querySelectorAll(\".tab-button\").forEach((tab) => {\n        this.tablistResizeObserver.observe(tab);\n      });\n      this.updateTabScrollState();\n    }\n\n    // If no tabs are selected by default, then select the first one\n    const selected = Array.from(\n      this.querySelectorAll(\".tab-button[data-selected]\"),\n    );\n    if (!selected.length) {\n      this.switchToTab(this.querySelector(\"button\").dataset.tabName);\n    }\n\n    // Intercept click events on Alert links at the\n    // top of the page and handle them in this component\n    Array.from(document.querySelectorAll(\"wx-point-alert-links a\")).forEach(\n      (alertAnchor) => {\n        alertAnchor.addEventListener(\"click\", this.handleAlertAnchorClick);\n      },\n    );\n\n    // Intercept click events on Alert spans that are in tab\n    // containers controlled by this component\n    this.addEventListener(\"click\", this.handleDescendantClick);\n    window.addEventListener(\"popstate\", this.handlePopState);\n\n    // Add needed event listeners\n    Array.from(this.querySelectorAll(\"button.tab-button\")).forEach((button) => {\n      button.addEventListener(\"click\", this.handleTabButtonClick);\n      button.addEventListener(\"keydown\", this.handleTabListKeydown);\n    });\n  }\n\n  disconnectedCallback() {\n    this.tablistResizeObserver?.disconnect();\n    this.removeEventListener(\"scroll\", this.updateTabScrollState, true);\n    window.removeEventListener(\"popstate\", this.handlePopState);\n\n    // Remove any event listeners\n    Array.from(this.querySelectorAll(\"button.tab-button\")).forEach((button) => {\n      button.removeEventListener(\"click\", this.handleTabButtonClick);\n      button.removeEventListener(\"keydown\", this.handleTabListKeydown);\n    });\n  }\n\n  updateTabScrollState() {\n    const tablist = this.querySelector(\"#point-page-tablist\");\n    const maxScroll = tablist ? tablist.scrollWidth - tablist.clientWidth : 0;\n    this.toggleAttribute(\"data-tabs-overflow\", maxScroll > 0);\n    this.toggleAttribute(\n      \"data-tabs-scroll-left\",\n      maxScroll > 0 && tablist.scrollLeft > 0,\n    );\n    // Allow for fractional scroll positions at the right edge.\n    this.toggleAttribute(\n      \"data-tabs-scroll-right\",\n      maxScroll > 0 && maxScroll - tablist.scrollLeft > 1,\n    );\n  }\n\n  navigateWithInitialHash() {\n    const hash = new URL(window.location).hash;\n    if (!hash || hash === \"\") {\n      return;\n    }\n\n    try {\n      const matchedTabButton = this.querySelector(\n        `[data-tab-name=\"${hash.replace(\"#\", \"\")}\"]`,\n      );\n      if (matchedTabButton) {\n        this.switchToTab(matchedTabButton.dataset.tabName);\n        matchedTabButton.parentElement.scrollIntoView();\n        return;\n      }\n\n      const childElement = this.querySelector(\n        `${hash},wx-tab-container, .wx-tab-container ${hash}`,\n      );\n      if (childElement) {\n        const tabContainer = childElement.closest(\".wx-tab-container\");\n        this.switchToTab(tabContainer.id);\n        if (childElement.matches(\".usa-accordion\")) {\n          this.toggleAccordion(childElement, true);\n          document.addEventListener(\"DOMContentLoaded\", () => {\n            this.scrollToAccordion(childElement);\n          });\n        }\n      }\n    } catch (e) {\n      // Guard against hashes that are not valid DOM identifiers. We can't\n      // prevent users from typing random stuff in the address bar, but we\n      // prevent our scripts from crashing if they do.\n    }\n  }\n\n  switchToTab(tabId) {\n    // First, deactivate all tabs\n    Array.from(this.querySelectorAll(\".tab-button, .wx-tab-container\")).forEach(\n      (element) => {\n        element.removeAttribute(\"data-selected\");\n        if (element.matches(\".tab-button\")) {\n          element.setAttribute(\"aria-expanded\", \"false\");\n          element.setAttribute(\"tabindex\", \"-1\");\n        }\n      },\n    );\n\n    // Active the tab button\n    const tabButton = this.querySelector(`[data-tab-name=\"${tabId}\"]`);\n    tabButton.setAttribute(\"data-selected\", \"\");\n    tabButton.setAttribute(\"aria-expanded\", \"true\");\n    tabButton.removeAttribute(\"tabindex\");\n\n    // Activate the corresponding container\n    const tabContainer = this.querySelector(`#${tabId}`);\n    tabContainer.setAttribute(\"data-selected\", \"\");\n\n    // Trigger a custom event for use externally\n    // when tabs switch\n    const event = new CustomEvent(\"wx:tab-switched\", {\n      detail: {\n        tabId,\n      },\n      bubbles: true,\n    });\n    this.dispatchEvent(event);\n  }\n\n  handleTabButtonClick(event) {\n    const tabButton = event.currentTarget;\n    this.switchToTab(tabButton.dataset.tabName);\n    // Since this was an actual click, update the hash\n    // of the site to the tab button's id and push it into the browser history\n    window.history.pushState(null, null, tabButton.dataset.url);\n  }\n\n  handlePopState() {\n    const currentPath = window.location.pathname;\n    const matchingTab = Array.from(\n      this.querySelectorAll(\".tab-button[data-url]\"),\n    ).find((tabButton) => {\n      const tabUrl = new URL(tabButton.dataset.url, window.location.origin);\n      return tabUrl.pathname === currentPath;\n    });\n\n    if (matchingTab) {\n      this.switchToTab(matchingTab.dataset.tabName);\n      matchingTab.focus({ preventScroll: true });\n    }\n  }\n\n  /**\n   * A catch-all listener for click events inside the navigator and any\n   * of its constituent tab content panes.\n   * We use this to filter out for wx-alert clicks, which will be handled\n   * separately.\n   */\n  handleDescendantClick(event) {\n    if (!event.target.matches(\"a\")) {\n      return;\n    }\n    const linkWrapper = event.target.closest(\".wx-alert-link\");\n    if (!linkWrapper) {\n      return;\n    }\n    this.navigateAlertAnchor(event.target);\n  }\n\n  navigateAlertAnchor(anchorEl) {\n    const hash = new URL(anchorEl.href).hash;\n    const accordionEl = this.querySelector(`${hash}.usa-accordion`);\n\n    if (accordionEl) {\n      // If we get here, then the element referred\n      // to by the href is a child of this tabbed\n      // navigator.\n      // We need to toggle to the correct tab pane\n      // to properly display and scroll to the element.\n      const tabContainer = accordionEl.closest(\".wx-tab-container\");\n      this.switchToTab(tabContainer.id);\n      this.toggleAccordion(accordionEl, true);\n\n      // Because we use a sticky position on\n      // the tab button area, the normal browser\n      // scrolling will not display the proper position\n      // to the user. Instead, we have to roll our\n      // own scrolling method\n      this.scrollToAccordion(accordionEl);\n      window.history.replaceState(null, null, hash);\n    }\n  }\n\n  handleAlertAnchorClick(event) {\n    event.preventDefault();\n    this.navigateAlertAnchor(event.currentTarget);\n  }\n\n  toggleAccordion(accordionElement, on = true) {\n    const button = accordionElement.querySelector(\n      \"button.usa-accordion__button\",\n    );\n    const content = accordionElement.querySelector(\".usa-accordion__content\");\n\n    if (on) {\n      button.setAttribute(\"aria-expanded\", \"true\");\n      content.removeAttribute(\"hidden\");\n    } else {\n      button.setAttribute(\"aria-expanded\", \"false\");\n      content.addAttribute(\"hidden\", \"\");\n    }\n  }\n\n  handleTabListKeydown(event) {\n    // Per W3C guidelines, arrow keys and other navigation\n    // keys should be used (instead of tab) to navigate the\n    // focus of tab buttons.\n    // See (https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-manual/)\n    const currentElement = event.target;\n    const isFirst = currentElement.matches(\":first-child\");\n    const isLast = currentElement.matches(\":last-child\");\n    if (event.key === \"ArrowRight\") {\n      if (isLast) {\n        event.target.parentElement\n          .querySelector(\".tab-button:first-child\")\n          .focus();\n      } else {\n        currentElement.nextElementSibling.focus();\n      }\n      event.preventDefault();\n    } else if (event.key === \"ArrowLeft\") {\n      if (isFirst) {\n        event.target.parentElement\n          .querySelector(\".tab-button:last-child\")\n          .focus();\n      } else {\n        currentElement.previousElementSibling.focus();\n      }\n      event.preventDefault();\n    } else if (event.key === \"Home\") {\n      event.target.parentElement\n        .querySelector(\".tab-button:first-child\")\n        .focus();\n      event.preventDefault();\n    } else if (event.key === \"End\") {\n      event.target.parentElement\n        .querySelector(\".tab-button:last-child\")\n        .focus();\n      event.preventDefault();\n    }\n  }\n\n  scrollToAccordion(accordionElement) {\n    const accordionTop = accordionElement.getBoundingClientRect().top;\n    const buttonArea = this.querySelector(\".tab-buttons\");\n    const buttonAreaHeight = buttonArea.getBoundingClientRect().height;\n    const scrollY = accordionTop + window.scrollY - buttonAreaHeight;\n    window.scrollTo(0, scrollY);\n  }\n}\n\nif (!window.customElements.get(\"wx-tabbed-nav\")) {\n  window.customElements.define(\"wx-tabbed-nav\", TabbedNavigator);\n}\n", "/**\n * Site navigation interaction\n */\n\n// Import the tabbed-nav component, which is used by\n// the search box popout\nimport \"./TabbedNavigator.js\";\n\nconst setupSiteSearchMenuButton = (siteSubmenuElement) => {\n  const button = siteSubmenuElement.querySelector(`button[aria-expanded]`);\n\n  button.addEventListener(\"click\", () => {\n    if (button.getAttribute(\"aria-expanded\") === \"false\") {\n      button.setAttribute(\"aria-expanded\", \"true\");\n    } else {\n      button.setAttribute(\"aria-expanded\", \"false\");\n    }\n  });\n};\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n  // Find the site search submenu and add a click listener\n  // to toggle the aria-expanded attribute.\n  const siteSearchSubmenu = document.getElementById(\"site-search-submenu\");\n  if (siteSearchSubmenu) {\n    setupSiteSearchMenuButton(siteSearchSubmenu);\n  }\n});\n", "/** @file Code to show/hide a \"scroll to top\" button. */\n\nconst mobileButton = document.querySelector(\".ride-up-button--mobile\");\nconst tabletButton = document.querySelector(\".ride-up-button--tablet\");\nconst footerRegion = document.querySelector(\"footer\");\n\nconst prefersReducedMotion = window.matchMedia?.(\n  \"(prefers-reduced-motion: reduce)\",\n)?.matches;\n\nlet scrollBracket = 0;\nlet bottomY = 0;\nlet hideThreshold = window.innerHeight * 1.75;\n// Show after scrolling up a 1/5 of a viewport.\nlet minScrollThreshold = window.innerHeight * 0.2;\nlet protectedArea = false;\n\nwindow.addEventListener(\"resize\", () => {\n  hideThreshold = window.innerHeight * 1.75;\n  minScrollThreshold = window.innerHeight * 0.2;\n});\n\nwindow.addEventListener(\n  \"scroll\",\n  () => {\n    // has the user scrolled more than 128 units?\n    if (window.scrollY / 128 !== scrollBracket) {\n      scrollBracket = window.scrollY >> 7;\n      // never show the buttons in the top 200vh or when the user scrolls down\n      if (window.scrollY < hideThreshold || window.scrollY > bottomY) {\n        mobileButton.classList.remove(\"ride-up-button--visible\");\n        tabletButton.classList.remove(\"ride-up-button--visible\");\n        bottomY = window.scrollY;\n      } else if (bottomY - window.scrollY > minScrollThreshold) {\n        mobileButton.classList.add(\"ride-up-button--visible\");\n        tabletButton.classList.add(\"ride-up-button--visible\");\n        bottomY = window.scrollY;\n      }\n    }\n  },\n  { passive: true },\n);\n\nconst scrollUp = () => {\n  if (prefersReducedMotion) {\n    window.scrollTo(0, 0);\n  } else {\n    window.scrollTo({ top: 0, behavior: \"smooth\" });\n  }\n};\n\nmobileButton.addEventListener(\"click\", scrollUp);\ntabletButton.addEventListener(\"click\", scrollUp);\n", "/**\n * WCAG compliant listbox component\n * See https://www.w3.org/WAI/ARIA/apg/patterns/listbox/\n */\n\nexport default class Listbox extends HTMLElement {\n  constructor() {\n    super();\n\n    this.template = document.createElement(\"template\");\n    this.template.innerHTML = `\n        <slot></slot>`;\n    this.attachShadow({ mode: \"open\" });\n    this.shadowRoot.append(this.template.content.cloneNode(true));\n\n    // Maps a key name to a handler for\n    // key events by the name of the key\n    this.keyMapping = {\n      ArrowUp: this.moveUp,\n      ArrowDown: this.moveDown,\n      Enter: this.selectPseudoFocused,\n      Home: this.moveHome,\n      End: this.moveEnd,\n    };\n\n    // Bind methods\n    this.bindEventListeners = this.bindEventListeners.bind(this);\n    this.unbindEventListeners = this.unbindEventListeners.bind(this);\n    this.handleFocus = this.handleFocus.bind(this);\n    this.handleKeyDown = this.handleKeyDown.bind(this);\n    this.handleItemsChanged = this.handleItemsChanged.bind(this);\n    this.moveDown = this.moveDown.bind(this);\n    this.moveUp = this.moveUp.bind(this);\n    this.moveHome = this.moveHome.bind(this);\n    this.moveEnd = this.moveEnd.bind(this);\n    this.selectPseudoFocused = this.selectPseudoFocused.bind(this);\n    this.pseudoFocusItem = this.pseudoFocusItem.bind(this);\n    this.selectItem = this.selectItem.bind(this);\n\n    this.bindEventListeners();\n  }\n\n  connectedCallback() {\n    this.bindEventListeners();\n    this.setAttribute(\"role\", \"listbox\");\n  }\n\n  disconnectedCallback() {\n    this.unbindEventListeners();\n  }\n\n  bindEventListeners() {\n    this.addEventListener(\"focus\", this.handleFocus);\n    this.shadowRoot\n      .querySelector(\"slot\")\n      .addEventListener(\"slotchange\", this.handleItemsChanged);\n    this.addEventListener(\"keydown\", this.handleKeyDown);\n    this.addEventListener(\"click\", this.handleClick);\n  }\n\n  unbindEventListeners() {\n    this.removeEventListener(\"focus\", this.handleFocus);\n    this.removeEventListener(\"keydown\", this.handleKeyDown);\n    this.removeEventListener(\"click\", this.handleClick);\n  }\n\n  handleFocus(e) {\n    // Automatically pseudo-focus the\n    // selected item.\n    // If there is no selected item,\n    // use the first item.\n    const selected = this.selection;\n    if (selected) {\n      this.pseudoFocusItem(selected);\n    } else {\n      const first = this.querySelector(`[role=\"option\"]`);\n      if (first) {\n        this.pseudoFocusItem(first);\n      }\n    }\n  }\n\n  handleClick(event) {\n    // We check to see if one of the options is in\n    // the chain of the bubbled click event\n    const closestOption = event.target.closest(`[role=\"option\"]`);\n    if (closestOption) {\n      event.currentTarget.selectItem(closestOption);\n    }\n  }\n\n  /**\n   * Attempts to look up a bound event handler\n   * for the given key, and calls it.\n   * Does nothing if the given key is not in\n   * the component's keyMapping dictionary.\n   */\n  handleKeyDown(event) {\n    if (event.target.keyMapping) {\n      const handler = event.target.keyMapping[event.key];\n      if (handler) {\n        handler.bind(this)(event);\n        event.preventDefault();\n      }\n    }\n  }\n\n  /**\n   * Handler for when slotted elements change.\n   * This is where we configure our listbox option\n   * elements as they are attached/removed.\n   * In this case, we add the data-option-index\n   * attribute to specify an order of options as they\n   * are presented in the dom (even though they can\n   * be nested in different lists).\n   * We also give each option an id based on the\n   * current component's id, if there isn't one already\n   * present.\n   */\n  handleItemsChanged(event) {\n    const host = event.target.getRootNode().host;\n    Array.from(host.querySelectorAll(`[role=\"option\"]`)).forEach(\n      (option, idx) => {\n        option.setAttribute(\"data-option-index\", idx);\n\n        // If the listbox itself has an id set, use\n        // that as a base for setting unique ids on\n        // each option. Do not set any id on an option\n        // that already has an id value.\n        // These ids are necessary for other wrapping\n        // components -- like a combobox -- that need\n        // to use aria-activedescendant to manage assistive\n        // technology focus capabilities.\n        if (!option.id && host.id) {\n          option.id = `${host.id}-option-${idx}`;\n        }\n      },\n    );\n  }\n\n  /**\n   * Pseudo Focus is what we are calling screenreader\n   * focus that is separate from the browser's DOM focus.\n   * It is managed primarily by the use of aria-activedescendant\n   * and should also be visually indicated through styling.\n   * This method removes the pseudo-focus state from all elements\n   * and if an element is also passed in, adds the state to that element.\n   * @param HTMLElement element\n   */\n  pseudoFocusItem(element) {\n    // If the passed on object is null or falsy,\n    // we un-focus all options in this component\n    Array.from(this.querySelectorAll(`[role=\"option\"]`)).forEach((option) => {\n      option.removeAttribute(\"data-pseudo-focus\");\n    });\n\n    if (element) {\n      element.setAttribute(\"data-pseudo-focus\", \"true\");\n\n      // Some listboxes might be inside an overflowed\n      // or scrolling container. Be sure to scroll the\n      // focused item into view\n      if (element.offsetTop < this.scrollTop) {\n        // user has scrolled past the item, so go back up\n        this.scrollTop = element.offsetTop;\n      } else if (\n        element.offsetTop + element.offsetHeight >\n        this.scrollTop + this.offsetHeight\n      ) {\n        // user is above the item, so go down\n        this.scrollTop =\n          element.offsetTop - this.offsetHeight + element.offsetHeight;\n      }\n\n      // If this component as the attribute\n      // `selection-follows-focus` set to \"true\",\n      // we also select the element we are focusing\n      if (this.getAttribute(\"selection-follows-focus\") === \"true\") {\n        this.selectItem(element);\n      }\n    }\n  }\n\n  /**\n   * If there is an item that is currently pseudo-focused,\n   * this method will call selectItem on that element.\n   */\n  selectPseudoFocused() {\n    const element = this.pseudoFocus;\n    if (element) {\n      this.selectItem(element);\n    }\n  }\n\n  /**\n   * Select item marks the provided element as being\n   * selected, for the purposes of listbox selection.\n   * It will also remove selection on any previously\n   * selected element(s).\n   * If the fireEvent parameter is set to true (as is by default),\n   * a change event will be dispatched from this component.\n   * @param HTMLElement element\n   * @param boolean fireEvent - Whether or not to dispatch\n   * a change event after selection. True by default.\n   */\n  selectItem(element, fireEvent = true) {\n    // De-select any that are already selected\n    Array.from(this.querySelectorAll(`[aria-selected=\"true\"]`)).forEach(\n      (selectedEl) => {\n        selectedEl.removeAttribute(\"aria-selected\");\n      },\n    );\n\n    // If there is an incoming element, select that one.\n    // By moving this into a cased control flow,\n    // we ensure that passing a falsy value for the element\n    // has the effect of clearing the current selection only.\n    if (element) {\n      element.setAttribute(\"aria-selected\", \"true\");\n      this.value = element.getAttribute(\"value\");\n    }\n\n    if (fireEvent) {\n      this.dispatchEvent(\n        new Event(\"change\", {\n          bubbles: true,\n          cancelable: true,\n        }),\n      );\n    }\n  }\n\n  /**\n   * Moves the pseudo focus one option previous\n   * in the listbox, based on overall option order.\n   * Navigation triggers the custom event wx:popup-nav\n   */\n  moveUp(event) {\n    // Find the element with the pseudo-focus.\n    // If there isn't one, bail.\n    const current = this.pseudoFocus;\n    if (current) {\n      const options = Array.from(this.querySelectorAll(`[role=\"option\"]`));\n      const currentIndex = options.indexOf(current);\n      const prev = currentIndex > 0 ? options[currentIndex - 1] : null;\n      // If prev does not exist, the call to pseudoFocusItem\n      // will un-pseudo focus everything the component\n      this.pseudoFocusItem(prev);\n      this.dispatchEvent(\n        new CustomEvent(\"wx:popup-nav\", {\n          bubbles: true,\n          detail: {\n            previous: current,\n            next: prev,\n            beyondTop: !prev && !this.pseudoFocus,\n            navCommand: \"moveUp\",\n          },\n        }),\n      );\n    }\n  }\n\n  /**\n   * Moves the pseudo focus to the next option\n   * element in the listbox, based on overall option\n   * order.\n   * Navigation triggers the custom event wx:popup-nav\n   */\n  moveDown(event) {\n    const current = this.pseudoFocus;\n    const options = Array.from(this.querySelectorAll(`[role=\"option\"]`));\n    if (!options.length) {\n      return;\n    }\n    const firstOption = options[0];\n    const lastOption = options[options.length - 1];\n    if (current === lastOption) {\n      return;\n    }\n    const currentIndex = options.indexOf(current);\n    const next = currentIndex >= 0 ? options[currentIndex + 1] : firstOption;\n\n    if (next && next !== current) {\n      this.pseudoFocusItem(next);\n      this.dispatchEvent(\n        new CustomEvent(\"wx:popup-nav\", {\n          bubbles: true,\n          detail: {\n            previous: current,\n            next: next,\n            navCommand: \"moveDown\",\n          },\n        }),\n      );\n    }\n  }\n\n  /**\n   * Moves the pseudo focus to the last option overall.\n   * Navigation triggers the custom event wx:popup-nav\n   */\n  moveHome(event) {\n    const current = this.pseudoFocus;\n    const options = Array.from(this.querySelectorAll(`[role=\"option\"]`));\n    const firstOption = options.length ? options[0] : null;\n    if (current && firstOption && current !== firstOption) {\n      this.pseudoFocusItem(firstOption);\n\n      this.dispatchEvent(\n        new CustomEvent(\"wx:popup-nav\", {\n          bubbles: true,\n          detail: {\n            previous: current,\n            next: firstOption,\n          },\n        }),\n      );\n    }\n  }\n\n  /**\n   * Moves the pseudo focus to the first option overall.\n   * Navigation triggers the custom event wx:popup-nav\n   */\n  moveEnd(event) {\n    const current = this.pseudoFocus;\n    const options = Array.from(this.querySelectorAll(`[role=\"option\"]`));\n    const lastOption = options.length ? options[options.length - 1] : null;\n    if (current && lastOption && current !== lastOption) {\n      this.pseudoFocusItem(lastOption);\n\n      this.dispatchEvent(\n        new CustomEvent(\"wx:popup-nav\", {\n          bubbles: true,\n          detail: {\n            previous: current,\n            next: lastOption,\n          },\n        }),\n      );\n    }\n  }\n\n  get selection() {\n    return this.querySelector(`[role=\"option\"][aria-selected=\"true\"]`);\n  }\n\n  get pseudoFocus() {\n    return this.querySelector(`[data-pseudo-focus=\"true\"]`);\n  }\n\n  static get observedAttributes() {\n    return [\"selection-follows-focus\"];\n  }\n}\n\nwindow.customElements.define(\"wx-listbox\", Listbox);\n", "import \"./combobox/listbox.js\";\n\nexport function navigateToElement(combobox) {\n  const popup = combobox.querySelector('[slot=\"popup\"]');\n  const selected = popup && popup.selection;\n  const targetUrl = selected && selected.getAttribute(\"data-value\");\n\n  if (targetUrl) {\n    window.location.href = targetUrl;\n  }\n}\n\n// Make navigateToElement available globally for inline onchange handler\nwindow.navigateToElement = navigateToElement;\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n  const sections = document.querySelectorAll(\".section-content h2[id]\");\n  const navLinks = document.querySelectorAll(\".usa-sidenav__item a\");\n\n  const observerOptions = {\n    root: null, // Uses the browser viewport\n    rootMargin: \"0px 0px -90% 0px\", // Triggers when section hits the upper-middle screen\n    threshold: 0,\n  };\n\n  const observerCallback = (entries) => {\n    entries.forEach((entry) => {\n      if (entry.isIntersecting) {\n        const id = entry.target.getAttribute(\"id\");\n\n        // Remove active class from all links\n        navLinks.forEach((link) => link.classList.remove(\"usa-current\"));\n\n        // Add active class to matching link\n        const activeLink = document.querySelector(\n          `.usa-sidenav__item a[href=\"#${id}\"]`,\n        );\n        if (activeLink) {\n          activeLink.classList.add(\"usa-current\");\n        }\n      }\n    });\n  };\n\n  // Set the first link as active on page load\n  if (navLinks.length > 0) {\n    navLinks[0].classList.add(\"usa-current\");\n  }\n\n  const observer = new IntersectionObserver(observerCallback, observerOptions);\n  sections.forEach((section) => observer.observe(section));\n});\n", "/** @file this is for the events to show and hide the wx-loader */\n\nconst hideNavigationLoader = () => {\n  document.querySelectorAll(\"wx-search-loading-indicator\").forEach((loader) => {\n    loader.setAttribute(\"aria-hidden\", true);\n  });\n};\n\n/**\n * If there is a navigation loader available on the page,\n * make sure that it is being displayed.\n *\n * Each loader is supposed to have a `loader-for` attribute\n * with one or more unique identifiers. Pick the desired loader\n * by passing the ID when emitting the event.\n */\nconst showNavigationLoader = (event) => {\n  const loaders = document.querySelectorAll(\"wx-search-loading-indicator\");\n  const activeNav = event.detail?.id;\n\n  loaders.forEach((loader) => {\n    const loaderIsFor = (loader.getAttribute(\"loader-for\") || \"\").split(\" \");\n    if (loaderIsFor.includes(activeNav)) {\n      loader.removeAttribute(\"aria-hidden\");\n    }\n  });\n  if (loaders.length) {\n    const text = gettext(\"js.loader.loading-text.01\");\n    window.dispatchEvent(new CustomEvent(\"wx-announce\", { detail: { text } }));\n  }\n};\n\nwindow.addEventListener(\"wx-hide-navigation-loader\", hideNavigationLoader);\nwindow.addEventListener(\"wx-show-navigation-loader\", showNavigationLoader);\n\n// When the page is shown, hide the navigation loader. This is the best we can\n// do to handle hiding it when the back button is clicked. This code is not\n// (necessarily) executed again when the back button is pressed. Instead, its\n// state may simply be popped from the history stack. The pageshow event is\n// fired any time this page is shown, regardless of source, and our event\n// listener would persist as part of the popped state. The downside is there's\n// a flash of the loader before it gets hidden.\n//\n// In the event that the browser has already unloaded this page's state from\n// the history stack (to recoup memory, for example), then the page will\n// reload entirely. In that case, the loader is already hidden.\nwindow.addEventListener(\"pageshow\", hideNavigationLoader);\n", "/** @file Set up browser geolocation and handle searching by it. */\n\n(() => {\n  const goToLocationPage = (latitude, longitude) => {\n    // Submit the form, so we get the same behavior regardless of how we end up\n    // navigating to the location page.\n    const form = document.querySelector(\"form[data-location-search]\");\n    form.setAttribute(\"action\", `/forecast/point/${latitude}/${longitude}`);\n\n    form.submit();\n  };\n\n  const removeBrowserLocationButtons = (buttons) => {\n    // make a copy and reverse so we don't accidentally clobber ourselves.\n    Array.from(buttons)\n      .reverse()\n      .forEach((button) => {\n        if (button) {\n          const sibling = button.previousElementSibling;\n          if (sibling) {\n            sibling.remove();\n          }\n          button.remove();\n        }\n      });\n  };\n\n  const setupBrowserGeolocation = async () => {\n    // There can be multiple buttons used for selecting the browser location.\n    // For example, one can be hidden away in the nav bar while another is\n    // present lower down on the page. Be sure to add the behavior to\n    // all buttons\n    const buttons = document.querySelectorAll(\n      \"button.weathergov-use-browser-location\",\n    );\n\n    // If the browser does not support the geolocation API, just bail out. Take\n    // the \"use my location\" button away too. Also bop out if we don't have a\n    // button for some reason. Just being safe.\n    if (!navigator.geolocation) {\n      removeBrowserLocationButtons(buttons);\n      return;\n    }\n\n    // Whether we should independently prompt the user prior to asking the browser\n    // for their location. IF we can detect existing permissions AND the user has\n    // not already granted or denied us, THEN we should prompt first. If we can't\n    // detect existing permissions, don't prompt because otherwise we end up\n    // putting up our prompt for that user every time they try to use their\n    // location.\n    let shouldPrompt = false;\n\n    if (navigator.permissions) {\n      try {\n        // Query for geolocation permissions.\n        const status = await navigator.permissions.query({\n          name: \"geolocation\",\n        });\n\n        // If the user has already denied location, we can go ahead and bail out.\n        // Changing browser settings is not detectable within the page, so they'll\n        // have to reload to get the option back anyway.\n        //\n        // Might need to reconsider this. It might be preferable to leave the\n        // button and show users a popup. There are several reasons we might get\n        // the \"denied\" state:\n        //\n        // 1. The web browser does not have permission from the operating system.\n        // 2. The web browser is configured to deny permission by default.\n        // 3. The user has denied access to our site in particular.\n        //\n        // In cases 1 and 2, users may not be aware of their settings. If we show\n        // the button and then popup a message when they click it letting them\n        // know they need to change their browser settings, maybe that's useful.\n        // The immediate drawback I can think of is we have no way of knowing\n        // whether it's a browser setting or an operating system setting, so we\n        // can't give them any more helpful advice than \"check your settings.\"\n        //\n        // In case 3, however, we should just leave the user alone. They have\n        // already said no, and that should be the end of it.\n        //\n        // Key important takeaway, though, is that \"denied\" means all of those\n        // things and it is impossible for us to know which.\n        if (status.state === \"denied\") {\n          removeBrowserLocationButtons(buttons);\n          return;\n        }\n\n        // If the user has not denied us permission, then we should show our own\n        // prompt if the user has not yet granted us permission.\n        shouldPrompt = status.state === \"prompt\";\n      } catch (_) {\n        // An exception in the permissions API likely indicates that the specific\n        // attribute we queried for isn't available. That doesn't mean the feature\n        // doesn't exist, though, so we should continue as if the permissions API\n        // doesn't exist at all and not use our prompt.\n      }\n    }\n\n    const buttonHandler = async (e) => {\n      // Stop any other event behavior, in case our button is inside a form\n      // or something.\n      e.preventDefault();\n      e.stopPropagation();\n\n      let proceed = true;\n\n      // If location is available and we know that the user has neither denied or\n      // granted us permission to use it, we will let them know before asking for\n      // it. It's kind of a double-opt-in.\n      if (shouldPrompt) {\n        const text = gettext(\"js.location-search.prompt.user-consent.01\");\n        proceed = window.confirm(text);\n      }\n\n      // If we don't know about the permission, we were already approved to use\n      // it, or the user has signaled that we can ask for it... ask for it!\n      if (proceed) {\n        // Show the loader animation, if available\n        window.dispatchEvent(\n          new CustomEvent(\"wx-show-navigation-loader\", {\n            detail: { id: e.currentTarget.getAttribute(\"id\") },\n          }),\n        );\n\n        navigator.geolocation.getCurrentPosition(\n          // Success callback\n          ({ coords: { latitude, longitude } }) => {\n            // Scale down the precision on these.\n            const lat = Math.round(latitude * 1_000) / 1_000;\n            const long = Math.round(longitude * 1_000) / 1_000;\n\n            // And navigate away!\n            goToLocationPage(lat, long);\n          },\n          // Error callback\n          ({ code, message }) => {\n            if (code > 1) {\n              // There was a problem getting the user's location. They allowed it,\n              // but the browser gave us an error.\n              // (Error code 1 is for when the user denies access to location, so\n              // for our purposes, that is not an error.)\n\n              const alertText = interpolate(\n                gettext(\"js.location-search.alert.geolocation-error.01\"),\n                [message],\n              );\n              alert(alertText);\n            }\n          },\n        );\n      }\n    };\n\n    Array.from(buttons).forEach((button) => {\n      button.addEventListener(\"click\", buttonHandler);\n    });\n  };\n  setupBrowserGeolocation();\n})();\n", "/**\n * WCAG compliant Combobox component\n */\nconst comboTemplate = `\n<div>\n  <slot name=\"input\"></slot>\n  <div>\n    <slot name=\"clear-button\"></slot>\n    <slot name=\"toggle-button\"></slot>\n  </div>\n</div>\n<slot name=\"popup\"></slot>\n`;\nexport default class Combobox extends HTMLElement {\n  constructor() {\n    super();\n    this.popup = null;\n\n    this.template = document.createElement(\"template\");\n    this.template.innerHTML = comboTemplate;\n    this.attachShadow({ mode: \"open\", delegatesFocus: true });\n    this.shadowRoot.append(this.template.content.cloneNode(true));\n    this.shadowRoot.addEventListener(\n      \"slotchange\",\n      this.handleSlotChange.bind(this),\n    );\n\n    // Bound methods\n    this.handleInput = this.handleInput.bind(this);\n    this.handleFocus = this.handleFocus.bind(this);\n    this.handleBlur = this.handleBlur.bind(this);\n    this.handleListboxMouseDown = this.handleListboxMouseDown.bind(this);\n    this.handleKeyDown = this.handleKeyDown.bind(this);\n    this.showPopup = this.showPopup.bind(this);\n    this.hidePopup = this.hidePopup.bind(this);\n    this.submit = this.submit.bind(this);\n    this.handlePopupChange = this.handlePopupChange.bind(this);\n    this.handleToggleClick = this.handleToggleClick.bind(this);\n    this.handleClearClick = this.handleClearClick.bind(this);\n  }\n\n  connectedCallback() {\n    // We need to ensure that the component has a unique id.\n    // This is used to compute popup option ids, which are necessary\n    // for the correct usage of aria-activedescendant and related\n    // pseudo-focus capabilites for assistive technologies.\n    if (!this.id) {\n      console.error(\n        `${this.tagName.toLowerCase()} requires an 'id' attribute to be set`,\n      );\n    }\n\n    // Keyboard and input based events will be listened for on\n    // the input element specifically, and handled on this component.\n    this.input = this.querySelector(`input[slot=\"input\"]`);\n    if (this.input) {\n      this.input.addEventListener(\"input\", this.handleInput);\n      this.input.addEventListener(\"keydown\", this.handleKeyDown);\n      this.input.addEventListener(\"focus\", this.handleFocus);\n      this.input.addEventListener(\"blur\", this.handleBlur);\n    }\n\n    this.addEventListener(\"focus\", this.handleFocus);\n    this.addEventListener(\"blur\", this.handleBlur);\n\n    // The wx:popup-nav is a custom event that will be fired by any\n    // element that is serving as the combobox's popup, such as a\n    // listbox, whenever a navigation event occurs in that element.\n    // In our most common use case, this is when the pseudoFocus\n    // is moved within a listbox that is slotted in this combobox.\n    this.addEventListener(\"wx:popup-nav\", this.handlePopupNav);\n\n    // Set up the appropriate event handlers for the clear button\n    // and the toggle button.\n    this.toggleButton = this.querySelector(`[slot=\"toggle-button\"]`);\n    if (this.toggleButton) {\n      this.toggleButton.addEventListener(\"click\", this.handleToggleClick);\n    }\n    this.clearButton = this.querySelector(`[slot=\"clear-button\"]`);\n    if (this.clearButton) {\n      this.clearButton.addEventListener(\"click\", this.handleClearClick);\n    }\n  }\n\n  /**\n   * Will attempt to show the popup child\n   * element for the combobox, while setting\n   * the appropriate aria attributes needed for\n   * both screenreading and styling.\n   */\n  showPopup() {\n    if (this.input) {\n      this.input.setAttribute(\"aria-expanded\", true);\n      this.setAttribute(\"expanded\", true);\n    }\n    if (this.popup) {\n      const target = this.popup.selection ?? this.popup.pseudoFocus;\n      if (target) {\n        this.popup.pseudoFocusItem(target);\n      }\n    }\n  }\n\n  /**\n   * Will hide the popup child element\n   * for the combobox, by setting the appropriate\n   * attributes needed for screenreading and styling\n   */\n  hidePopup() {\n    this.removeAttribute(\"expanded\");\n    this.input.removeAttribute(\"aria-expanded\");\n    this.input.removeAttribute(\"aria-activedescendant\");\n  }\n\n  /**\n   * Find the closest ancestor <form> element.\n   * If there is one, trigger its submit() method.\n   * Because we work with an input, it will be\n   * considered part of that form and its data will be\n   * used as part of the form action.\n   */\n  submit() {\n    this.closest(\"form\")?.submit();\n  }\n\n  /**\n   * Handle any changes to slotted elements.\n   * This is where we bind and/or remove listeners for\n   * the component that serves as the popup for the\n   * combobox (usually a listbox).\n   * We do it here instead of at component callback time\n   * because we want to leave open the possibility for\n   * popups to be dynamically swapped out if needed,\n   * and to still have all the appropriate event handling\n   * setup when that happens.\n   * This handler also sets ids on the popup itself if\n   * there isn't already one, as well as updating the\n   * combobox input aria-controls to map to the\n   * incoming popup element.\n   */\n  handleSlotChange(event) {\n    const name = event.target.getAttribute(\"name\");\n    const assigned = event.target.assignedElements();\n\n    if (name === \"popup\") {\n      // If there is an existing popup that was attached,\n      // remove any event listeners from it.\n      if (this.popup) {\n        this.popup.removeEventListener(\"change\", this.handlePopupChange);\n        this.popup.removeEventListener(\n          \"mousedown\",\n          this.handleListboxMouseDown,\n        );\n      }\n\n      // Now check if there is a new popup assigned or\n      // if the slot is empty. Either way assign the value\n      // to the stored popup\n      this.popup = assigned.length ? assigned[0] : null;\n      if (this.popup) {\n        this.popup.addEventListener(\"change\", this.handlePopupChange);\n        this.popup.addEventListener(\"mousedown\", this.handleListboxMouseDown);\n\n        // If the listbox element does not have an id set, use\n        // this component's id as a base for creating a unique id.\n        // The listbox options need to have their own unique ids\n        // for the use of aria-activedescendant, which handles pseudo\n        // focus in assistive technologies\n        if (!this.popup.id) {\n          this.popup.id = `${this.id}-popup`;\n\n          // Trigger slotchange event manually\n          this.popup.innerHTML = this.popup.innerHTML;\n        }\n        this.input.setAttribute(\"aria-controls\", this.popup.id);\n\n        this.handlePopupChange({ target: this.popup });\n      }\n    }\n  }\n\n  /**\n   * We need to stop the default behavior of mousedown\n   * on the listbox, so that the normal browser doesn't\n   * try to change focus/blur. This is what otherwise happens\n   * in FF and Safari (but not Chrome), where click events\n   * in the listbox will never be hit because by that time\n   * the input has already blurred and lost focus.\n   */\n  handleListboxMouseDown(event) {\n    event.preventDefault();\n  }\n\n  /**\n   * Handle specific popup navigation event cases.\n   * We want to open the popup if the user tries to\n   * navigate down and it's not already open.\n   * Likewise, if we are already at the top of the popup and\n   * we move up again, it should hide the component.\n   * An additional behavior that is crucial for accessibility\n   * is that any popup child that has pseudofocus will be mapped\n   * to the combobox input's aria-activedescendant, which is a\n   * way of mapping screenreader focus that is separate from\n   * browser element focus.\n   */\n  handlePopupNav(event) {\n    if (event.detail.beyondTop) {\n      // If the user has navigated beyond the top option in the list\n      // (usually a #moveUp when the first item is already selected),\n      // we hide the list\n      this.hidePopup();\n    } else if (\n      event.detail.navCommand === \"moveDown\" &&\n      !event.detail.previous\n    ) {\n      // If there was no previous focus element and we are moving down,\n      // we should attempt to open the popup. This scenario can occur if:\n      // 1. The user has focused the input, revelating the popup, then\n      // 2. The user navigated up past the first item, closing the popup, then\n      // 3. The user navigated down again\n      this.showPopup();\n    }\n\n    // If there is an item pseudoFocused, we update\n    // aria-activedescendant.\n    // Otherwise, remove the attribute entirely\n    if (event.target.pseudoFocus) {\n      this.input.setAttribute(\n        \"aria-activedescendant\",\n        event.target.pseudoFocus.id,\n      );\n    } else {\n      this.input.removeAttribute(\"aria-activedescendant\");\n    }\n  }\n\n  /**\n   * Popup elements can fire generic change events.\n   * In the case of a combobox, we expect that the target\n   * of the event can have a selection.\n   * Set the value of the combobox input to the provided selection.\n   */\n  handlePopupChange(event) {\n    if (event.target.selection) {\n      this.hidePopup();\n\n      const option = event.target.selection;\n      const value = option.getAttribute?.(\"data-value\");\n\n      // \"data-value-for\" is the id of a hidden input used to store the \"real\" value\n      const id = this.input.getAttribute(\"data-value-for\");\n\n      if (value && id) {\n        const element = this.querySelector(`input[name=${id}][type=hidden]`);\n        if (element) element.value = value;\n      }\n\n      this.input.value = event.target.selection.textContent || null;\n    } else {\n      this.input.value = null;\n    }\n\n    if (this.input.value) {\n      const clearButton = this.querySelector(`[slot=\"clear-button\"]`);\n      clearButton.classList.remove(\"empty\");\n    }\n  }\n\n  /**\n   * The combobox keydown event handler will attempt\n   * to find a keyMapping dictionary on its slotted popup\n   * component, such as is available for a listbox.\n   * This allows us to trigger the popup's handlers for the given\n   * keys, without needed to implement them all over again\n   * in this component.\n   */\n  handleKeyDown(event) {\n    const popupIsOpen = this.getAttribute(\"expanded\") === \"true\";\n    if (this.popup) {\n      if (event.key === \"Escape\") {\n        this.popup.pseudoFocusItem(null);\n        return this.hidePopup();\n      } else if (event.key === \"ArrowDown\" && !popupIsOpen) {\n        // We focus the first item\n        this.popup.pseudoFocusItem(\n          this.popup.querySelector(`[role=\"option\"][data-option-index=\"0\"]`),\n        );\n        return this.showPopup();\n      }\n\n      // Otherwise, let the listbox handle the event, so long\n      // as it has a keymapping defined.\n      if (this.popup.keyMapping) {\n        const handler = this.popup.keyMapping[event.key];\n        if (handler) {\n          const boundHandler = handler.bind(this.popup);\n          boundHandler(event);\n          event.preventDefault();\n        }\n      }\n    }\n  }\n\n  /**\n   * Cick handler for the toggle button.\n   * Will show or hide the popup depending\n   * on the state.\n   */\n  handleToggleClick(event) {\n    event.preventDefault();\n    if (this.getAttribute(\"expanded\") === \"true\") {\n      this.hidePopup();\n    } else {\n      this.showPopup();\n      this.input.focus();\n    }\n  }\n\n  /**\n   * Click handler for the clear button.\n   * Will clear the input and reset state on the\n   * popup.\n   */\n  handleClearClick(event) {\n    event.preventDefault();\n    this.popup.pseudoFocusItem(null);\n    this.input.value = \"\";\n    this.handleInput();\n    this.input.focus();\n    this.hidePopup();\n  }\n\n  /**\n   * Text input handler for the combobox input element.\n   * Will attempt to call the `filterText()` method of any\n   * slotted popup element using the input's current value.\n   * Will also update the presence of the clear button based\n   * on the input's new value.\n   */\n  handleInput(event) {\n    if (this.popup) {\n      if (!this.hasAttribute(\"expanded\")) {\n        this.showPopup();\n      }\n      if (this.popup.filterText) {\n        this.popup.filterText(this.input.value);\n      }\n    }\n\n    // Hide or show the clear button's slot\n    // based on the input value's presence\n    const clearButton = this.querySelector(`[slot=\"clear-button\"]`);\n    if (this.input.value && this.input.value !== \"\") {\n      clearButton.classList.remove(\"empty\");\n    } else {\n      clearButton.classList.add(\"empty\");\n    }\n  }\n\n  /**\n   * When gaining focus, show the popup but only\n   * if there are actual options available in the popup.\n   */\n  handleFocus(event) {\n    const hasItems = this.popup.querySelectorAll(`[role=\"option\"]`).length;\n    if (hasItems) {\n      this.showPopup();\n    }\n  }\n\n  /**\n   * Hide the popup when this element loses focus.\n   */\n  handleBlur(event) {\n    // Only perform blur operations if the target of the\n    // event is outside of the combobox component\n    const ancestor = event.relatedTarget?.closest(this.tagName);\n    if (ancestor !== this) {\n      this.popup.pseudoFocusItem(null);\n      this.hidePopup();\n      if (this.popup && this.popup.selection) {\n        this.input.value = this.popup.selection.textContent;\n        const clearButton = this.querySelector(`[slot=\"clear-button\"]`);\n        clearButton.classList.remove(\"empty\");\n      }\n    }\n  }\n\n  /**\n   * The only attribute we listen for changes on is 'disabled',\n   * which reacts by disabling (or re-enabling) all constinuent\n   * elements that can be disabled. This prevents any key or mouse\n   * events from triggering event handlers.\n   */\n  attributeChangedCallback(name, oldVal, newVal) {\n    if (name === \"disabled\" && newVal === \"true\") {\n      this.input.setAttribute(\"disabled\", true);\n      this.clearButton.setAttribute(\"disabled\", true);\n      this.toggleButton.setAttribute(\"disabled\", true);\n      this.hidePopup();\n    } else if (name === \"disabled\") {\n      this.input.removeAttribute(\"disabled\");\n      this.clearButton.removeAttribute(\"disabled\");\n      this.toggleButton.removeAttribute(\"disabled\");\n    }\n  }\n\n  get isExpanded() {\n    return this.getAttribute(\"expanded\") === \"true\";\n  }\n\n  static get observedAttributes() {\n    return [\"disabled\"];\n  }\n}\n\nif (!window.customElements.get(\"wx-combobox\")) {\n  window.customElements.define(\"wx-combobox\", Combobox);\n}\n", "/** @file Manage a visitor's recent locations in local storage. */\n\nconst RECENT_LOC_STORAGE = \"wxgov_recent_locations\";\n\n/**\n * @typedef {Object} RecentLocation from local storage\n * @property {string} url the point forecast url for the location\n * @property {string} text the human-readable location name\n */\n\n/**\n * Get the list of recent locations from local storage.\n *\n * @returns {RecentLocation}\n */\nexport function getRecentLocations() {\n  try {\n    const existing = localStorage.getItem(RECENT_LOC_STORAGE);\n    const parsed = JSON.parse(existing ?? \"[]\");\n\n    // Check if any saved locations still have the old /point/lat/long url format\n    const needsUpdate = parsed.filter(({ url }) => url.startsWith(\"/point\"));\n\n    if (needsUpdate.length > 0) {\n      // Prepend the forecast path to any URLs that need it\n      const updated = parsed.map(({ url, ...rest }) => ({\n        ...rest,\n        url: url.startsWith(\"/forecast\") ? url : `/forecast${url}`,\n      }));\n      localStorage.setItem(RECENT_LOC_STORAGE, JSON.stringify(updated));\n      return updated;\n    }\n    return parsed;\n  } catch (e) {\n    return [];\n  }\n}\n\n/**\n * Insert a recent location into local storage.\n * If the location already exists, move it to the top.\n *\n * @param {RecentLocation} obj - the recent location\n */\nexport function addRecentLocation(obj) {\n  try {\n    // First we need to see if there are any existing\n    // items already saved in the saved searches array\n    const existing = localStorage.getItem(RECENT_LOC_STORAGE);\n    const parsed = JSON.parse(existing ?? \"[]\");\n    // Now remove any items for the same URL. This way we don't\n    // end up having a whole list of the same place\n    const filtered = parsed.filter(({ url }) => url !== obj.url);\n    // Just keep the most recent ten.\n    const sliced = filtered.slice(0, 9);\n\n    // Put the new entry at the front of the list\n    sliced.unshift(obj);\n\n    // Now serialize and save\n    localStorage.setItem(RECENT_LOC_STORAGE, JSON.stringify(sliced));\n  } catch (e) {\n    /* do nothing */\n  }\n}\n", "import Listbox from \"./listbox.js\";\nimport { getRecentLocations, addRecentLocation } from \"../recent-locations.js\";\nimport Timer from \"../timer.js\";\n\nconst debouncer = new Timer();\n\nconst getRedirectUrlFromAddressCandidate = (addressCandidate) => {\n  const { type, lat, lon, abbr } = addressCandidate;\n  const typeLowercase = type.toLowerCase();\n  if (typeLowercase === \"county\") {\n    return `/wx/location-search/county/${lat}/${lon}`;\n  } else if (typeLowercase === \"state or province\" && abbr) {\n    return `/forecast/state/${abbr}`;\n  }\n  return `/forecast/point/${lat}/${lon}`;\n};\n\n/**\n * @typedef {Object} Suggestion from geocode.arcgis.com\n * @property {boolean} isCollection\n * @property {string} magicKey\n * @property {string} text the human-readable location name\n */\n\n/**\n * @typedef {Object} SavedLocation from local storage\n * @property {string} url the point forecast url for the location\n * @property {string} text the human-readable location name\n */\n\n/**\n * Helper function. Creates an `li` element for a given choice.\n *\n * @param {number} setSize the number of results in the list\n * @param {string|undefined} describedby the id of the element which describes the list (optional)\n * @param {Suggestion|SavedLocation} suggestion the data for this item\n * @param {number} idx the item's position in the list\n * */\nconst makeListItemFromResultItem = (setSize, describedby, suggestion, idx) => {\n  const item = document.createElement(\"li\");\n  item.innerText = suggestion.text;\n  item.setAttribute(\"role\", \"option\");\n  item.setAttribute(\"aria-setsize\", setSize);\n  item.setAttribute(\"posinset\", idx + 1);\n  item.setAttribute(\"aria-selected\", false);\n  if (describedby) {\n    item.setAttribute(\"aria-describedby\", describedby);\n  }\n  if (suggestion.magicKey) {\n    item.setAttribute(\"data-magic-key\", suggestion.magicKey);\n  } else if (suggestion.url) {\n    item.setAttribute(\"data-url\", suggestion.url);\n  } else {\n    return null;\n  }\n  return item;\n};\n\n/**\n * Given a `ul` for location search results, create all the child `li`s.\n *\n * @param {HTMLElement} resultListElement the container for the result list\n * @param {HTMLElement|undefined} ariaDescEl the element which describes the list (optional)\n * @param {Array<Suggestion|SavedLocation>} suggestions\n */\nconst makeListFromResult = (resultListElement, ariaDescEl, suggestions) => {\n  resultListElement.innerHTML = \"\";\n  const setSize = suggestions.length;\n  const describedby = ariaDescEl.id;\n  const newItems = suggestions.map((suggestion, idx) => {\n    return makeListItemFromResultItem(setSize, describedby, suggestion, idx);\n  });\n  resultListElement.append(...newItems);\n};\n\nexport default class LocationListbox extends Listbox {\n  constructor() {\n    super();\n\n    // Private property defaults\n    this.inputDelay = 250;\n\n    // Bound component methods\n    this.updateSavedSearches = this.updateSavedSearches.bind(this);\n    this.getSearchResults = this.getSearchResults.bind(this);\n    this.handlePopupNav = this.handlePopupNav.bind(this);\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.addEventListener(\"wx:popup-nav\", this.handlePopupNav);\n\n    // If there is a place set via attribute, we add\n    // it to the saved search results\n    if (this.dataset.place) {\n      addRecentLocation({\n        text: this.dataset.place,\n        url: window.location.pathname,\n      });\n    }\n    this.updateSavedSearches();\n  }\n\n  /**\n   * Override selectItem to first fetch the location data\n   * (either from cache or live) for the option with the\n   * given magicKey\n   */\n  selectItem(element) {\n    // For consistency, let's force even the regular calls\n    // to selectItem to be wrapped as promises\n    const selectItemPromise = new Promise((resolve) => {\n      resolve(super.selectItem(element));\n    });\n\n    // If the incoming element is falsy, just return the\n    // promise to call the super version.\n    if (!element) {\n      return selectItemPromise;\n    }\n\n    // Otherwise, if the option's data-url attribute exists, use that.\n    if (element.getAttribute(\"data-url\")) {\n      return new Promise((resolve) => {\n        if (this.getAttribute(\"auto-submit\") === \"true\") {\n          addRecentLocation({\n            text: element.innerText,\n            url: element.getAttribute(\"data-url\"),\n          });\n          const form = this.closest(\"form[data-location-search]\");\n          form.setAttribute(\"action\", element.getAttribute(\"data-url\"));\n          form.submit();\n          // Show the loader animation, if available\n          window.dispatchEvent(\n            new CustomEvent(\"wx-show-navigation-loader\", {\n              detail: { id: this.getAttribute(\"id\") },\n            }),\n          );\n        }\n\n        resolve(super.selectItem(element));\n      });\n    }\n\n    // Otherwise, attempt to get cached/fetched\n    // geographic data and add that to the option element\n    // dataset/attributes.\n    // This is so consumers of the change event can see the result.\n    if (element.dataset.magicKey) {\n      return this.getGeodataForKey(element.dataset.magicKey).then((geoData) => {\n        if (geoData) {\n          element.setAttribute(\"data-lat\", geoData.lat);\n          element.setAttribute(\"data-lon\", geoData.lon);\n          if (this.getAttribute(\"auto-submit\") === \"true\") {\n            const formUrl = getRedirectUrlFromAddressCandidate(geoData);\n\n            addRecentLocation({\n              text: element.innerText,\n              url: formUrl,\n            });\n\n            const form = this.closest(\"form[data-location-search]\");\n            form.setAttribute(\"action\", formUrl);\n            form.submit();\n            // Show the loader animation, if available\n            window.dispatchEvent(\n              new CustomEvent(\"wx-show-navigation-loader\", {\n                detail: { id: this.getAttribute(\"id\") },\n              }),\n            );\n          }\n        }\n        super.selectItem(element);\n      });\n    }\n\n    return selectItemPromise;\n  }\n\n  /**\n   * For this subclass of the listbox, we want to\n   * prefetch and cache location data for the magicKey\n   * for any result list item. We speculatively do so\n   * whenever a given item receives the pseudoFocus.\n   */\n  handlePopupNav(event) {\n    if (this.pseudoFocus) {\n      const key = this.pseudoFocus.dataset.value;\n      this.cacheLocationGeodata(key);\n    }\n  }\n\n  /**\n   * Retrieve saved locations from local storage and\n   * insert them into the popup, filtering first by\n   * `filterTerm` if one is given.\n   */\n  updateSavedSearches(filterTerm) {\n    const savedSearchesGroup = this.querySelector(\n      '[role=\"group\"].saved-searches',\n    );\n    const savedSearchesLabel = this.querySelector(\n      '[role=\"heading\"].saved-searches',\n    );\n    if (savedSearchesGroup) {\n      let saved = getRecentLocations();\n\n      // Clear any existing search items in the element.\n      // We will regenerate them.\n      savedSearchesGroup.innerHTML = \"\";\n\n      if (filterTerm) {\n        const match = filterTerm.toLowerCase();\n        saved = saved.filter((option) =>\n          option.text.toLowerCase().includes(match),\n        );\n      }\n\n      // If there are no saved searches, we should hide\n      // the list and the label together\n      if (!saved.length) {\n        savedSearchesLabel?.classList?.add?.(\"hidden\");\n        savedSearchesGroup.classList.add(\"hidden\");\n      } else {\n        savedSearchesLabel?.classList?.remove?.(\"hidden\");\n        savedSearchesGroup.classList.remove(\"hidden\");\n        makeListFromResult(savedSearchesGroup, savedSearchesLabel, saved);\n      }\n    }\n  }\n\n  async getSearchResults(text) {\n    const response = await this.searchLocation(text);\n    if (response.ok) {\n      const data = await response.json();\n      return data;\n    }\n    return { suggestions: [] };\n  }\n\n  /** Announce updated search results in an Aria live region. */\n  announceResults() {\n    const numResults = this.querySelectorAll(\"li\").length;\n    const translation = ngettext(\n      \"js.location-combo-box.aria.search-updated.01\",\n      \"js.location-combo-box.aria.search-updated.01-plural\",\n      numResults,\n    );\n    const transWithCount = interpolate(translation, [numResults]);\n    window.dispatchEvent(\n      new CustomEvent(\"wx-announce\", {\n        detail: { text: transWithCount, delay: 0 },\n      }),\n    );\n  }\n\n  async filterText(text) {\n    debouncer.start(async () => {\n      const data = await this.getSearchResults(text);\n      const resultListElement = this.querySelector(\n        '[role=\"group\"].data-results',\n      );\n      const headerElement = this.querySelector('[role=\"heading\"].data-results');\n      if (resultListElement) {\n        resultListElement.remove();\n        makeListFromResult(resultListElement, headerElement, data.suggestions);\n        this.append(resultListElement);\n      }\n      this.updateSavedSearches(text);\n      this.announceResults();\n    }, this.inputDelay);\n  }\n\n  /**\n   * Asynchronously fetches specific location data\n   * for a given search result, stashing it away in\n   * the cache\n   */\n  async cacheLocationGeodata(magicKey) {\n    if (!window.sessionStorage.getItem(magicKey)) {\n      const result = await this.getLocationGeodata(magicKey);\n      window.sessionStorage.setItem(magicKey, JSON.stringify(result));\n    }\n  }\n\n  /**\n   * Attempts to retrieve location data for a search\n   * result by its magicKey from the cache.\n   * If not present, will make the Arc API call\n   * to fetch the data.\n   */\n  async getGeodataForKey(magicKey) {\n    const cached = window.sessionStorage.getItem(magicKey);\n    if (!cached) {\n      return this.getLocationGeodata(magicKey);\n    }\n    return JSON.parse(cached);\n  }\n\n  async getLocationGeodata(magicKey) {\n    const url = `https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?magicKey=${magicKey}&f=json&_=1695666335115&outFields=Type,RegionAbbr`;\n    const response = await fetch(url, {\n      headers: { \"Content-Type\": \"application/json\" },\n    });\n    const results = await response.json();\n    return this.processLocationGeodata(results);\n  }\n\n  processLocationGeodata(results) {\n    if (\n      !results.error &&\n      Array.isArray(results.candidates) &&\n      results.candidates.length > 0\n    ) {\n      // Take the first available location (highest score)\n      const firstCandidate = results.candidates[0];\n      const { x, y } = firstCandidate.location;\n      const type = firstCandidate.attributes.Type;\n      const abbr = firstCandidate.attributes.RegionAbbr;\n\n      const lat = Math.round(y * 1_000) / 1_000;\n      const lon = Math.round(x * 1_000) / 1_000;\n      return { lat, lon, type, abbr };\n    }\n\n    return null;\n  }\n\n  async searchLocation(text) {\n    const url = `https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest?f=json&countryCode=USA%2CPRI%2CVIR%2CGUM%2CASM&category=Land+Features%2CBay%2CChannel%2CCove%2CDam%2CDelta%2CGulf%2CLagoon%2CLake%2COcean%2CReef%2CReservoir%2CSea%2CSound%2CStrait%2CWaterfall%2CWharf%2CAmusement+Park%2CHistorical+Monument%2CLandmark%2CTourist+Attraction%2CZoo%2CCollege%2CBeach%2CCampground%2CGolf+Course%2CHarbor%2CNature+Reserve%2COther+Parks+and+Outdoors%2CPark%2CRacetrack%2CScenic+Overlook%2CSki+Resort%2CSports+Center%2CSports+Field%2CWildlife+Reserve%2CAirport%2CFerry%2CMarina%2CPier%2CPort%2CResort%2CPostal%2CPopulated+Place&maxSuggestions=10&_=1695666335097&text=${text}`;\n    return fetch(url, { headers: { \"Content-Type\": \"application/json\" } });\n  }\n}\n\nif (!window.customElements.get(\"wx-location-listbox\")) {\n  window.customElements.define(\"wx-location-listbox\", LocationListbox);\n}\n", "/** @file Manage a visitor's recent/favorite locations in local storage. */\n\nconst SAVED_LOC_STORAGE = \"wxgov_saved_locations\";\nconst RECENT_LOC_STORAGE = \"wxgov_recent_locations\";\nconst TAB_REGEX = new RegExp(\"\\/(?:alerts|today|7-day|maps|analysis).*\", \"i\");\n\n/**\n * @typedef {Object} SavedLocations from local storage\n * @property {Object.<string, string>} hashed object of saved location (lowercase-text : url)\n * @property {Array<SavedLocation>} sorted sorted list of saved locations\n */\n\n/**\n * @typedef {Object} SavedLocation from local storage\n * @property {string} text the human-readable location name\n * @property {string} url the point forecast url for the location\n */\n\n/**\n * Remove a trailing forecast tab while preserving the rest of the URL.\n * @param {string} url location URL\n * @returns {string} location URL without a tab suffix\n */\nfunction normalizeLocationUrl(url) {\n  if (typeof url !== \"string\") return url;\n\n  return url.replace(TAB_REGEX, \"\");\n}\n\n/**\n * Normalize both URL representations in a saved-location collection.\n * @param {SavedLocations} storage saved location collection\n * @returns {SavedLocations} normalized collection\n */\nfunction normalizeSavedLocationStorage(storage) {\n  if (storage?.hashed) {\n    storage.hashed = Object.fromEntries(\n      Object.entries(storage.hashed).map(([text, url]) => [\n        text,\n        normalizeLocationUrl(url),\n      ]),\n    );\n  }\n  if (storage?.sorted) {\n    storage.sorted = storage.sorted.map((location) => ({\n      ...location,\n      url: normalizeLocationUrl(location.url),\n    }));\n  }\n  return storage;\n}\n\n/**\n * Get JSON parsed local storage for saved locations\n * @returns {SavedLocations}\n */\nfunction getParsedSavedLocationStorage() {\n  const storage = localStorage.getItem(SAVED_LOC_STORAGE);\n  const parsedStorage = JSON.parse(storage ?? \"{}\");\n  return normalizeSavedLocationStorage(parsedStorage);\n}\n\n/**\n * Set saved location local storage to new JSON item\n * @param {SavedLocations} newStorage saved location collection to set\n */\nfunction setSavedLocationStorage(newStorage) {\n  localStorage.setItem(\n    SAVED_LOC_STORAGE,\n    JSON.stringify(normalizeSavedLocationStorage(newStorage)),\n  );\n}\n\n/**\n * Get the sorted list of saved locations from local storage\n * @returns {Array<SavedLocation>}\n */\nexport function getSavedLocations() {\n  const current = getParsedSavedLocationStorage();\n\n  return current?.sorted ? current.sorted : [];\n}\n\n/**\n * Returns if location is within the saved location local storage\n * @param {string} locText location to match if in saved location storage\n * @returns {boolean}\n */\nexport function hasSavedLocation(locText) {\n  let found = false;\n  if (locText?.length) {\n    const locLower = locText?.toLowerCase();\n    const existing = getParsedSavedLocationStorage();\n    found = existing?.hashed && Object.hasOwn(existing.hashed, locLower);\n  }\n  return found;\n}\n\n/**\n * Adds a new location to saved locations in local storage, maintaining sorted order\n * @param {SavedLocation} obj saved location object to add to storage\n */\nexport function addSavedLocation(obj) {\n  // Validate obj\n  if (!obj && !obj?.text?.toLowerCase() && !obj?.url) return;\n\n  const textLower = obj.text.toLowerCase();\n  const existing = getParsedSavedLocationStorage();\n  const hashed = existing?.hashed ?? {};\n  const sorted = existing?.sorted ?? [];\n\n  if (!Object.hasOwn(hashed, textLower)) {\n    if (sorted?.length) {\n      // Find the correct sorted location to insert new element based on text\n      const largerElemIndex = sorted.findIndex((item) => {\n        return item?.text?.toLowerCase() > textLower;\n      });\n      // Insert new element before the larger element\n      if (largerElemIndex === -1) {\n        sorted.push(obj);\n      } else {\n        sorted.splice(largerElemIndex, 0, obj);\n      }\n    } else {\n      sorted.push(obj);\n    }\n    hashed[textLower] = obj?.url;\n    setSavedLocationStorage({\n      hashed: hashed,\n      sorted: sorted,\n    });\n  }\n}\n\n/**\n * Removes the saved location from storage that matches the location string\n * @param {string} loc location string to remove from storage\n */\nexport function removeSavedLocation(loc) {\n  const locLower = loc?.toLowerCase();\n  const existing = getParsedSavedLocationStorage();\n  const existingSorted = existing?.sorted ?? [];\n  const existingHashed = existing?.hashed ?? {};\n  const existingElemIdx = existingSorted.findIndex((item) => {\n    return item?.text?.toLowerCase() === locLower;\n  });\n\n  if (existingElemIdx > -1) {\n    // Remove element in place and update storage with new collection\n    existingSorted.splice(existingElemIdx, 1);\n    delete existingHashed[loc.toLowerCase()];\n    setSavedLocationStorage({ sorted: existingSorted, hashed: existingHashed });\n  }\n}\n", "/**\n * Saved location section handler\n */\nimport {\n  getSavedLocations,\n  hasSavedLocation,\n  addSavedLocation,\n  removeSavedLocation,\n} from \"./saved-locations.js\";\n\nclass SavedLocationsSection extends HTMLElement {\n  constructor() {\n    super();\n\n    this.displayClass = \"\";\n    this.hideClass = \"display-none\";\n    this.buttonItemIdPrefix = \"saved-locations-section-btn-\";\n    this.ariaCheckedAttribute = \"aria-checked\";\n\n    this.savedLocations = {};\n\n    this.sectionType = this.dataset?.type ?? \"front\";\n    this.sectionCols = this.dataset?.columns ?? \"true\";\n    this.sectionEl = this.querySelector(\n      `#saved-locations-section-${this.sectionType}`,\n    );\n    this.templateLi = this.querySelector(\n      `#saved-locations-section-${this.sectionType}-li`,\n    );\n\n    this.bindEventListeners = this.bindEventListeners.bind(this);\n    this.unbindEventlisteners = this.unbindEventlisteners.bind(this);\n\n    this.initSection = this.initSection.bind(this);\n    this.hideList = this.hideList.bind(this);\n    this.showList = this.showList.bind(this);\n\n    this.addListButtonEvents = this.addListButtonEvents.bind(this);\n    this.createList = this.createList.bind(this);\n    this.createListItem = this.createListItem.bind(this);\n    this.getListColumnClass = this.getListColumnClassList.bind(this);\n\n    this.onListButtonClick = this.onListButtonClick.bind(this);\n    this.onSavedLocationsButtonAdd = this.onSavedLocationsButtonAdd.bind(this);\n    this.onSavedLocationsButtonRemove =\n      this.onSavedLocationsButtonRemove.bind(this);\n    this.onSectionLocationAdd = this.onSectionLocationAdd.bind(this);\n    this.onSectionLocationRemove = this.onSectionLocationRemove.bind(this);\n  }\n\n  connectedCallback() {\n    this.bindEventListeners();\n    this.initSection();\n  }\n\n  disconnectedCallback() {\n    this.unbindEventlisteners();\n  }\n\n  bindEventListeners() {\n    window.addEventListener(\n      \"wx-saved-locations:button-add\",\n      this.onSavedLocationsButtonAdd,\n    );\n    window.addEventListener(\n      \"wx-saved-locations:button-remove\",\n      this.onSavedLocationsButtonRemove,\n    );\n    window.addEventListener(\n      \"wx-saved-locations:section-add\",\n      this.onSectionLocationAdd,\n    );\n    window.addEventListener(\n      \"wx-saved-locations:section-remove\",\n      this.onSectionLocationRemove,\n    );\n  }\n  unbindEventlisteners() {\n    window.removeEventListener(\n      \"wx-saved-locations:button-add\",\n      this.onSavedLocationsButtonAdd,\n    );\n    window.removeEventListener(\n      \"wx-saved-locations:button-remove\",\n      this.onSavedLocationsButtonRemove,\n    );\n    window.removeEventListener(\n      \"wx-saved-locations:section-add\",\n      this.onSectionLocationAdd,\n    );\n    window.removeEventListener(\n      \"wx-saved-locations:section-remove\",\n      this.onSectionLocationRemove,\n    );\n  }\n\n  initSection() {\n    const currentLocations = getSavedLocations();\n    if (currentLocations?.length) {\n      this.createList(currentLocations);\n      this.showList();\n    } else {\n      this.hideList();\n    }\n  }\n\n  hideList() {\n    this.sectionEl?.classList?.add(this.hideClass);\n  }\n\n  showList() {\n    this.sectionEl?.classList?.remove(this.hideClass);\n  }\n\n  cleanString(str) {\n    return str?.trim()?.replace(/\\W/g, \"\")?.toLowerCase();\n  }\n\n  createList(locations) {\n    const listUl = this.querySelector(\"ul\");\n    const listColumnClass = this.getListColumnClassList(locations.length);\n    if (listColumnClass?.length) listUl.classList.add(...listColumnClass);\n\n    const newElems = [];\n\n    for (let index = 0; index < locations.length; index++) {\n      const { text, url } = locations[index];\n      const element = this.createListItem(text, url);\n      newElems.push(element);\n    }\n    listUl.replaceChildren();\n    listUl.append(...newElems);\n    this.addListButtonEvents();\n  }\n\n  createListItem(text, url) {\n    const cleanedText = this.cleanString(text);\n    this.savedLocations[text] = true;\n\n    // Clone the template\n    const templateLi = this.templateLi;\n    const clonedLi = document.importNode(templateLi.content, true);\n\n    // Update the template\n    const liButton = clonedLi.querySelector(\"button\");\n    liButton.id = `${liButton.id}${cleanedText}`;\n    liButton.setAttribute(\"data-loctext\", text);\n    liButton.setAttribute(\"data-locurl\", url);\n    liButton.setAttribute(\"aria-label\", `Saved location ${text}`);\n\n    const liAnchor = clonedLi.querySelector(\"a\");\n    const anchorId = `saved-locations-section-label-${cleanedText}`;\n    liAnchor.id = anchorId;\n    liAnchor.setAttribute(\"href\", url);\n    liAnchor.innerText = text;\n\n    return clonedLi;\n  }\n\n  getListColumnClassList(itemLength) {\n    if (this.sectionCols === \"false\") return \"\";\n    const columnBase = \"use-columns\",\n      classRange = [\n        { min: 25, class: \"--x4\" },\n        { min: 17, class: \"--x3\" },\n        { min: 9, class: \"--x2\" },\n      ];\n    let columnPostfix;\n\n    for (let index = 0; index < classRange.length; index++) {\n      if (itemLength >= classRange[index].min) {\n        columnPostfix = classRange[index].class;\n        break;\n      }\n    }\n\n    return columnPostfix ? [columnBase, `${columnBase}${columnPostfix}`] : [];\n  }\n\n  addListButtonEvents() {\n    const buttonElems = this.querySelectorAll(\"button.saved-locations-button\");\n    buttonElems.forEach((btn) => {\n      btn.addEventListener(\"click\", this.onListButtonClick);\n    });\n  }\n\n  onListButtonClick(e) {\n    const currentTarget = e.currentTarget;\n    const currentLoc = currentTarget.dataset.loctext;\n    const currentUrl = currentTarget.dataset.locurl;\n    if (this.savedLocations[currentLoc] === true) {\n      currentTarget.setAttribute(this.ariaCheckedAttribute, false);\n      this.savedLocations[currentLoc] = false;\n      removeSavedLocation(currentLoc);\n      window.dispatchEvent(\n        new CustomEvent(\"wx-saved-locations:section-remove\", {\n          detail: {\n            text: currentLoc,\n            url: currentUrl,\n            caller: this.sectionType,\n          },\n        }),\n      );\n    } else {\n      currentTarget.setAttribute(this.ariaCheckedAttribute, true);\n      this.savedLocations[currentLoc] = true;\n      addSavedLocation({ text: currentLoc, url: currentTarget.dataset.locurl });\n      window.dispatchEvent(\n        new CustomEvent(\"wx-saved-locations:section-add\", {\n          detail: {\n            text: currentLoc,\n            url: currentUrl,\n            caller: this.sectionType,\n          },\n        }),\n      );\n    }\n  }\n\n  onSavedLocationsButtonAdd(e) {\n    // If already in list, set the button to saved, otherwise add to the list\n    const detail = e.detail ?? {};\n    const addLocation = detail?.text ?? \"\";\n    if (addLocation in this.savedLocations) {\n      if (this.savedLocations[addLocation] === false) {\n        // Get the button\n        const buttonId = `${this.buttonItemIdPrefix}${this.cleanString(addLocation)}`;\n        const buttonElem = this.querySelector(`#${buttonId}`);\n        buttonElem.setAttribute(this.ariaCheckedAttribute, true);\n        this.savedLocations[addLocation] = true;\n      }\n    } else {\n      // Find where to insert new node\n      const currentSavedLocations = getSavedLocations();\n      const currentList = this.querySelectorAll(\"li\");\n      const currentListUl = this.querySelector(\"ul\");\n\n      const currentLocationIndex = currentSavedLocations.findIndex((loc) => {\n        return addLocation === loc.text;\n      });\n\n      if (currentLocationIndex !== -1) {\n        // Gather previous list's column class and get new class\n        const currentColumnClass = this.getListColumnClassList(\n          currentList.length,\n        );\n        const newColumnClass = this.getListColumnClassList(\n          currentList.length + 1,\n        );\n\n        // Create new DOM element\n        const currentLocationItem = currentSavedLocations[currentLocationIndex];\n        const newListItem = this.createListItem(\n          currentLocationItem.text,\n          currentLocationItem.url,\n        );\n\n        // Attach event listener to button\n        const newListButton = newListItem.querySelector(\n          \"button.saved-locations-button\",\n        );\n        newListButton.addEventListener(\"click\", this.onListButtonClick);\n\n        // Insert into the list\n        if (currentList?.length === 0) {\n          currentListUl.append(newListItem);\n        } else if (currentLocationIndex === 0) {\n          currentList[0].before(newListItem);\n        } else {\n          currentList[currentLocationIndex - 1].after(newListItem);\n        }\n        // Update column class\n        if (currentColumnClass?.length)\n          currentListUl.classList.remove(...currentColumnClass);\n        if (newColumnClass?.length)\n          currentListUl.classList.add(...newColumnClass);\n\n        // Update local tracking\n        this.savedLocations[addLocation] = true;\n\n        // If previously hidden, now show\n        if (currentList?.length === 0) {\n          this.showList();\n        }\n      }\n    }\n  }\n\n  onSavedLocationsButtonRemove(e) {\n    // Disable the necessary button but don't remove from the list yet\n    const detail = e.detail ?? {};\n\n    const addLocation = detail?.text ?? \"\";\n    if (addLocation in this.savedLocations) {\n      if (this.savedLocations[addLocation] === true) {\n        // Get the button and disable\n        const buttonId = `${this.buttonItemIdPrefix}${this.cleanString(addLocation)}`;\n        const buttonElem = this.querySelector(`#${buttonId}`);\n        buttonElem.setAttribute(this.ariaCheckedAttribute, false);\n        this.savedLocations[addLocation] = false;\n      }\n    }\n  }\n\n  onSectionLocationAdd(e) {\n    // Another section has set item to saved, now update this list also\n    const detail = e.detail ?? {};\n    const caller = detail?.caller;\n    if (caller === this.sectionType) return;\n\n    const addLocation = detail?.text ?? \"\";\n\n    if (addLocation in this.savedLocations) {\n      if (this.savedLocations[addLocation] === false) {\n        // Get the button\n        const buttonId = `${this.buttonItemIdPrefix}${this.cleanString(addLocation)}`;\n        const buttonElem = this.querySelector(`#${buttonId}`);\n        buttonElem.setAttribute(this.ariaCheckedAttribute, true);\n        this.savedLocations[addLocation] = true;\n      }\n    }\n  }\n\n  onSectionLocationRemove(e) {\n    // Another section has set item to unsaved, now update this list also\n    const detail = e.detail ?? {};\n    const caller = detail?.caller;\n    if (caller === this.sectionType) return;\n\n    const removeLocation = detail?.text ?? \"\";\n\n    if (removeLocation in this.savedLocations) {\n      if (this.savedLocations[removeLocation] === true) {\n        // Get the button and disable\n        const buttonId = `${this.buttonItemIdPrefix}${this.cleanString(removeLocation)}`;\n        const buttonElem = this.querySelector(`#${buttonId}`);\n        buttonElem.setAttribute(this.ariaCheckedAttribute, false);\n        this.savedLocations[removeLocation] = false;\n      }\n    }\n  }\n}\n\nif (!window.customElements.get(\"wx-saved-locations-section\")) {\n  window.customElements.define(\n    \"wx-saved-locations-section\",\n    SavedLocationsSection,\n  );\n}\n", "/**\n * Pull the application ID from a specific meta tag, if the tag is there.\n * If it is not present, the given environment is not set up for using RUM.\n */\nconst getRUMApplicationId = () => {\n  const tag = document.querySelector(`meta[data-name=\"aws-rum-app-id\"]`);\n  if (!tag || !tag.getAttribute(\"content\")) {\n    console.warn(`No valid RUM application id found in markup.`);\n    return null;\n  }\n  return tag.getAttribute(\"content\");\n};\n\n/**\n * General configuration for our environment(s)\n */\nconst config = {\n  sessionSampleRate: 1.0,\n  identityPoolId: \"us-east-1:d53843c8-350a-4c14-a929-8c0b2844cf62\",\n  endpoint: \"https://dataplane.rum.us-east-1.amazonaws.com\",\n  telemetries: [\"performance\", \"errors\", \"http\"],\n  allowCookies: true,\n  enableXRay: false,\n  signing: true, // If you have a public resource policy and wish to send unsigned requests please set this to false\n  disableAutoPageView: true,\n  customEvents: { enabled: true },\n};\n\n/**\n * Extracted version of the anonymous function in snippet used for creating\n * the RUM client and attaching it to the window as a global.\n */\nconst createAwsRumClient = (name, id, version, region, scriptSrc, config) => {\n  window.AwsRumClient = {\n    q: [],\n    n: name,\n    i: id,\n    v: version,\n    r: region,\n    c: config,\n  };\n\n  window[name] = function (config, p) {\n    window.AwsRumClient.q.push({ c: config, p });\n  };\n\n  const scriptTag = document.createElement(\"script\");\n  scriptTag.async = true;\n  scriptTag.src = scriptSrc;\n  document.head.insertBefore(\n    scriptTag,\n    document.getElementsByTagName(\"script\")[0],\n  );\n};\n\n/**\n * Helper function for determining page groups based on the\n * provided path. Used for giving stable labels to different kinds\n * of URLs.\n */\nconst pageGroups = (path) => {\n  const match = path.match(\n    /^\\/(forecast\\/county|forecast\\/state|cms|forecast\\/point|place)/,\n  );\n  if (!match) {\n    // this pathname is not part of a RUM page group\n    return null;\n  }\n  const what = match[1];\n  // rename endpoints for clarity on the RUM side\n  switch (what) {\n    case \"forecast/point\":\n      return \"forecast\";\n    case \"forecast/county\":\n      return \"county\";\n    case \"forecast/state\":\n      return \"state\";\n    default:\n      return what;\n  }\n};\n\nconst isUsingHTMX = () => {\n  // We determine if we are using HTMX by checking that the\n  // HTMX script element is on the page\n  const script = document.querySelector(`script[src*=\"point-htmx\"]`);\n  if (script) {\n    return true;\n  }\n  return false;\n};\n\nconst getPointForecastPageName = (path) => {\n  const match = path.match(\n    /^\\/forecast\\/point\\/[0-9-.]+\\/[0-9-.]+\\/(alerts|analysis|7-day|today|maps)/,\n  );\n  if (!match) {\n    return null;\n  }\n  return match[1];\n};\n\n/**\n * Sets up the various page views and custom events\n * that we want to record.\n * This function should be run after the RUM client is\n * successfully initialized, as it expects there to be a\n * global (window) function named 'cwr'\n */\nconst setupRecording = () => {\n  // Add event listeners for TabbedNavigator interactions.\n  // If we are using HTMX, we will also want to add listeners\n  // for when the tab content loads\n\n  // When a user switches to another tab\n  // in any TabbedNavigator\n  document.addEventListener(\"wx:tab-switched\", (event) => {\n    const rumEventData = {\n      path: window.location.pathname,\n      isPointPage: !!window.location.pathname.match(/\\/forecast\\/point/),\n      usingHTMX: isUsingHTMX(),\n      tabId: event.detail.tabId,\n    };\n    window.cwr(\"recordEvent\", { type: \"tabbed_nav_click\", data: rumEventData });\n  });\n\n  // When tab contents have loaded behind the scenes\n  // via HTMX-like functionality\n  document.addEventListener(\"wx:tab-content-loaded\", (event) => {\n    const rumEventData = {\n      path: window.location.pathname,\n      isPointPage: !!window.location.pathname.match(/\\/forecast\\/point/),\n      usingHTMX: isUsingHTMX(),\n      tabId: event.detail.tabId,\n    };\n    window.cwr(\"recordEvent\", {\n      type: \"tab_content_loaded\",\n      data: rumEventData,\n    });\n  });\n\n  // When there was an error loading tab contents in the background\n  // using HTMX like functionality\n  document.addEventListener(\"wx:tab-content-error\", (event) => {\n    const rumEventData = {\n      path: window.location.pathname,\n      isPointPage: !!window.location.pathname.match(/\\/forecast\\/point/),\n      usingHTMX: isUsingHTMX(),\n      tabId: event.detail.tabId,\n      errorCode: event.detail.status,\n    };\n    window.cwr(\"recordEvent\", {\n      type: \"tab_content_error\",\n      data: rumEventData,\n    });\n  });\n\n  const pathname = window.location.pathname;\n  const pageTags = [];\n\n  // Get the initial \"page name\" tag.\n  // This will be the type of page, ie\n  // 'forecast', 'county', 'state' or the literal\n  // url in all other cases\n  const pageTypeTag = pageGroups(pathname);\n  if (pageTypeTag) {\n    pageTags.push(pageTypeTag);\n  }\n\n  // Next, check to see if this is a point forecast page or\n  // not. If so, add the 'point-forecast' tag, as well as the\n  // specific tab page name tag for point forecasts\n  const pointForecastTabPageName = getPointForecastPageName(pathname);\n  if (pointForecastTabPageName) {\n    pageTags.push(\"point-forecast\", pointForecastTabPageName);\n  }\n\n  // If we are in 'HTMX' mode, lets add that as a tag\n  // as well\n  if (isUsingHTMX()) {\n    pageTags.push(\"using-htmx\");\n  }\n\n  // Finally, record the pageView\n  if (pageTags.length) {\n    window.cwr(\"recordPageView\", { pageId: pathname, pageTags });\n  } else {\n    window.cwr(\"recordPageView\", { pageId: pathname });\n  }\n};\n\n/**\n * Initialize the RUM client if there is a valid application id,\n * then set up the kinds of page views and custom events\n * we want to record.\n * Note that an invalid or missing application id will return early\n */\n(function () {\n  // If there is not a valid application id, immediately\n  // return to prevent initialization of RUM.\n  const APPLICATION_ID = getRUMApplicationId();\n  if (!APPLICATION_ID) {\n    return;\n  }\n  const APPLICATION_VERSION = \"1.0.0\";\n  const APPLICATION_REGION = \"us-east-1\";\n\n  // Initialize the RUM client on the window\n  createAwsRumClient(\n    \"cwr\",\n    APPLICATION_ID,\n    APPLICATION_VERSION,\n    APPLICATION_REGION,\n    \"https://client.rum.us-east-1.amazonaws.com/1.x/cwr.js\",\n    config,\n  );\n\n  // Set up the page views and custom events for recording\n  setupRecording();\n})();\n", "import Timer from \"./timer.js\";\n\n// Store a reference to the original fetch function\nwindow._fetch = window.fetch;\n\nconst replaceFetch = () => {\n  const banner = document.querySelector(\"#wx-offline-banner__container\");\n  const template = document.querySelector(\"#wx-offline-banner__template\");\n  const importantHosts = JSON.parse(\n    document.getElementById(\"third-party-site-list\").textContent,\n  );\n  importantHosts.push(window.location.host);\n  const maxDelay = 1800000; // 30 minutes\n\n  const debouncer = {\n    banner: new Timer(),\n    ariaLive: new Timer(),\n  };\n  const metronome = {\n    ping: new Timer(),\n  };\n\n  const hideOfflineBanner = () => {\n    try {\n      banner.innerHTML = \"\";\n      metronome.ping.stop();\n      const text = gettext(\"js.offline-banner.aria.you-are-back-online.01\");\n      window.dispatchEvent(\n        new CustomEvent(\"wx-announce\", { detail: { text } }),\n      );\n    } catch (_) {\n      /* do nothing */\n    }\n  };\n\n  const checkOffline = () => {\n    if (!navigator.onLine) {\n      metronome.ping.reset();\n    } else {\n      window._fetch\n        .apply(this, [\"/health/\"])\n        .then((_) => hideOfflineBanner())\n        .catch((_) => metronome.ping.reset());\n    }\n  };\n\n  const showOfflineBanner = () => {\n    try {\n      if (!banner.children.length) {\n        debouncer.ariaLive.start(() => {\n          banner.appendChild(template.content.cloneNode(true));\n          banner.scrollIntoView();\n        }, 1000);\n      }\n      metronome.ping.start(checkOffline);\n    } catch (_) {\n      /* do nothing */\n    }\n  };\n\n  const wait = (delay) => new Promise((resolve) => setTimeout(resolve, delay));\n\n  /**\n   * This is a wrapper around the original window.fetch, to provide\n   * automatic retry and offline banners.\n   *\n   * By default, it retries 10 times, but you can pass `wxMaxRetries`:\n   *\n   *     fetch(\"url\", {..}, {wxMaxRetries: 5})\n   *\n   * The original fetch is at window._fetch.\n   */\n  window.fetch = (resource, options = {}) => {\n    const maxRetries = options.wxMaxRetries || 10;\n    const tries = options.wxTries || 1;\n    let requestedHost;\n    try {\n      requestedHost = new URL(resource).host;\n    } catch (error) {\n      /* do nothing */\n    }\n\n    if (importantHosts.includes(requestedHost)) {\n      return window._fetch(resource, options).catch((error) => {\n        showOfflineBanner();\n        if (tries <= maxRetries) {\n          options.wxTries = tries + 1;\n          options.wxMaxRetries = maxRetries;\n          const array = new Uint32Array(1);\n          const rand = crypto.getRandomValues(array)[0];\n          const jitter = (rand % 100) + 1;\n          const delay = Math.min(500 * 2 ** tries + jitter, maxDelay);\n          return wait(delay).then(() => window.fetch(resource, options));\n        } else {\n          throw error;\n        }\n      });\n    } else {\n      return window._fetch(resource, options);\n    }\n  };\n};\n\nif (document.readyState === \"loading\") {\n  document.addEventListener(\"DOMContentLoaded\", replaceFetch, {\n    once: true,\n  });\n} else {\n  replaceFetch();\n}\n", "import Timer from \"./timer.js\";\n\nconst debouncer = new Timer();\n/**\n * Cache the text here to compare text between calls.\n *\n * This is needed because some screenreaders will not announce \"repeat\" messages.\n */\nlet text = \"\";\n\n/**\n * Adds a span of screenreader only text to\n * a page-wide aria-live region,\n * which is itself also hidden.\n * The update is on a 1 second delay, which is preferred\n * based on convos with USWDS.\n *\n * To use:\n *   const text = gettext(\"js.<keyFromDjangojs.po>.01\"));\n *   window.dispatchEvent(new CustomEvent(\"wx-announce\", { detail: { text }}));\n */\nconst updateAriaLive = (e) => {\n  const delay = Number.isFinite(e.detail?.delay) ? e.detail?.delay : 1000;\n  // check if this is a repeat message\n  if (text === e.detail?.text) {\n    // if so, append a non-breaking space\n    text += \"\\u00A0\";\n  } else {\n    // otherwise, use the new text\n    text = e.detail?.text;\n  }\n  debouncer.start(() => {\n    const span = document.createElement(\"span\");\n    span.innerText = text;\n    const liveRegion = document.querySelector(\"#sr-only\");\n    liveRegion.innerHTML = \"\";\n    liveRegion.append(span);\n  }, delay);\n};\n\nwindow.addEventListener(\"wx-announce\", updateAriaLive);\n", "/**\n * Accordion is a custom HTML element which toggles the visibility of a element.\n *\n * Example usage:\n *\n *    <wx-accordion>\n *      <button type=\"button\"\n *        aria-expanded=\"true\"\n *        aria-controls=\"a3\"\n *      >\n *        Third Amendment (open)\n *      </button>\n *      <template>\n *        Third Amendment (closed)\n *      </template>\n *      <div id=\"a3\" class=\"usa-prose\">\n *        <p>\n *          No Soldier shall, in time of peace be quartered in any house,\n *          without the consent of the Owner, nor in time of war,\n *          but in a manner to be prescribed by law.\n *        </p>\n *      </div>\n *    </wx-accordion>\n *\n * The `<template>` tag can be used to provide alternative content for the button\n * when the accordion is toggled shut.\n *\n * The `<button>` must start in the `aria-expanded=\"true\"` state. This will render\n * the contents of the accordion accessible, even if the JavaScript fails.\n *\n * The target area does _not_ need to be a child of `<wx-accordion>`.\n */\nclass Accordion extends HTMLElement {\n  target;\n  template;\n  buttonContent = {\n    expanded: null,\n    collapsed: null,\n  };\n  toggleButton;\n\n  async connectedCallback() {\n    // attach onClick event listener to the toggle button\n    this.toggleButton = this.querySelector(\"button[aria-expanded='true']\");\n    if (!this.toggleButton) throw new Error(\"Accordion: button not found\");\n    this.toggleButton.addEventListener(\"click\", this.toggle);\n\n    // clone the toggle button's content into memory\n    this.template = this.querySelector(\"template\");\n    this.buttonContent.expanded = document.createDocumentFragment();\n    this.buttonContent.expanded.append(\n      ...this.toggleButton.cloneNode(true).childNodes,\n    );\n    this.buttonContent.collapsed = this.template?.content?.cloneNode?.(true);\n\n    // find the element whose visibility is to be toggled\n    const contentId = this.toggleButton.getAttribute(\"aria-controls\");\n    if (!contentId)\n      throw new Error(\"Accordion: missing aria-controls on button\");\n    this.target = document.body.querySelector(`#${contentId}`);\n    if (!this.target) throw new Error(\"Accordion: target not found\");\n\n    this.collapse();\n  }\n\n  disconnectedCallback() {\n    this.toggleButton?.removeEventListener(\"click\", this.toggle);\n  }\n\n  collapse = () => {\n    this.target.classList.add(\"display-none\");\n    this.toggleButton.setAttribute(\"aria-expanded\", \"false\");\n    if (this.template) {\n      this.toggleButton.replaceChildren(\n        this.buttonContent.collapsed.cloneNode(true),\n      );\n    }\n  };\n\n  expand = () => {\n    this.target.classList.remove(\"display-none\");\n    this.toggleButton.setAttribute(\"aria-expanded\", \"true\");\n    if (this.template) {\n      this.toggleButton.replaceChildren(\n        this.buttonContent.expanded.cloneNode(true),\n      );\n    }\n  };\n\n  toggle = () => {\n    if (this.toggleButton) {\n      const isCollapsed =\n        this.toggleButton.getAttribute(\"aria-expanded\") !== \"true\";\n      if (isCollapsed) {\n        this.expand();\n      } else {\n        this.collapse();\n      }\n    }\n  };\n}\n\nif (!window.customElements.get(\"wx-accordion\")) {\n  window.customElements.define(\"wx-accordion\", Accordion);\n}\n", "/**\n * Generic WCAG Tabs component\n * ------------------------------------------\n * This is a progressively enhanced component.\n * tab, tablist, and tabpanel elements are expected\n * to have the correct `role` attributes and other\n * aria references.\n * See\n * https://www.w3.org/WAI/ARIA/apg/patterns/tabs/\n */\nclass Tabs extends HTMLElement {\n  constructor() {\n    super();\n\n    // Bound methods\n    this.handleTabClick = this.handleTabClick.bind(this);\n    this.handleKeyDown = this.handleKeyDown.bind(this);\n  }\n\n  connectedCallback() {\n    Array.from(this.querySelectorAll('[role=\"tab\"]')).forEach((tabElement) => {\n      tabElement.addEventListener(\"click\", this.handleTabClick);\n    });\n    this.addEventListener(\"keydown\", this.handleKeyDown);\n  }\n\n  disconnectedCallback() {\n    this.removeEventListener(\"keydown\", this.handleKeyDown);\n    Array.from(this.querySelectorAll('[role=\"tab\"]')).forEach((tabElement) => {\n      tabElement.removeEventListener(\"click\", this.handleTabClick);\n    });\n  }\n\n  /**\n   * The click handler should update the tab's\n   * aria-selected attribute, and also update the\n   * data-tabpanel-selected attribute on its corresponding\n   * tabpanel.\n   * Any hiding/showing of tabpanel content should be\n   * handled by implementor's CSS\n   */\n  handleTabClick(event) {\n    const tab = event.target.closest('[role=\"tab\"]');\n    const panelId = tab.getAttribute(\"aria-controls\");\n    const panel = document.getElementById(panelId);\n    if (panel) {\n      this.tabs.forEach((tabElement) => {\n        tabElement.setAttribute(\"aria-selected\", false);\n      });\n      tab.setAttribute(\"aria-selected\", true);\n      this.tabpanels.forEach((tabpanelElement) => {\n        tabpanelElement.setAttribute(\"data-tabpanel-selected\", false);\n      });\n      panel.setAttribute(\"data-tabpanel-selected\", true);\n      panel.setAttribute(\"aria-labelledby\", tab.id);\n      this.setAttribute(\"data-selected\", panelId);\n    }\n\n    window.dispatchEvent(new CustomEvent(\"wx-tab-focused\", { detail: tab }));\n  }\n\n  /**\n   * Binds key handling events as specified in\n   * the WCAG recommendations\n   */\n  handleKeyDown(event) {\n    const currentFocus = this.querySelector(\n      '[role=\"tab\"]:focus,[role=\"tab\"]:focus-within',\n    );\n    const firstItemInFocus = currentFocus.matches(\n      '[role=\"tab\"]:first-child:focus, [role=\"tab\"]:first-child:focus-within',\n    );\n    const lastItemInFocus = currentFocus.matches(\n      '[role=\"tab\"]:last-child:focus, [role=\"tab\"]:last-child:focus-within',\n    );\n    let handled = false;\n    if (event.key === \"ArrowLeft\") {\n      if (firstItemInFocus) {\n        this.focusTab(this.querySelector('[role=\"tab\"]:last-child'));\n      } else {\n        this.focusTab(currentFocus.previousElementSibling);\n      }\n      handled = true;\n    } else if (event.key === \"ArrowRight\") {\n      if (lastItemInFocus) {\n        this.focusTab(this.querySelector('[role=\"tab\"]:first-child'));\n      } else {\n        this.focusTab(currentFocus.nextElementSibling);\n      }\n      handled = true;\n    } else if (event.key === \"Space\" || event.key === \"Enter\") {\n      currentFocus.click();\n      handled = true;\n    } else if (event.key === \"Home\") {\n      this.focusTab(this.querySelector('[role=\"tab\"]:first-child'));\n      handled = true;\n    } else if (event.key === \"End\") {\n      this.focusTab(this.querySelector('[role=\"tab\"]:last-child'));\n      handled = true;\n    }\n\n    if (handled) {\n      event.stopPropagation();\n      event.preventDefault();\n    }\n  }\n\n  focusTab(anElement) {\n    // It is not required that the element with the role tab\n    // be a focusable element. In such cases, we need to\n    // check its children for elements that can receive focus.\n    // We do this in the simplest possible way, limiting ourselves\n    // to a, button, or any element with a tabindex\n    const matchString = \"a, button, [tabindex]\";\n    if (anElement.matches(matchString)) {\n      anElement.focus();\n    } else {\n      const childFocusElement = anElement.querySelector(matchString);\n      if (childFocusElement) {\n        childFocusElement.focus();\n      }\n    }\n  }\n\n  get tabs() {\n    return Array.from(this.querySelectorAll('[role=\"tab\"]'));\n  }\n\n  get tabpanels() {\n    return this.tabs.map((tabElement) => {\n      const panelId = tabElement.getAttribute(\"aria-controls\");\n      return document.getElementById(panelId);\n    });\n  }\n}\n\nif (!window.customElements.get(\"wx-tabs\")) {\n  window.customElements.define(\"wx-tabs\", Tabs);\n}\n", "const getRelevantDOMNodes = () => ({\n  alerts: [...document.querySelectorAll(\"wx-alerts > div[data-alert]\")],\n  legends: [\n    ...document.querySelectorAll(\n      \".wx_alert_map_legend > [data-alert-map-legend-level]\",\n    ),\n  ],\n  emptyState: [...document.querySelectorAll(\"[data-no-alerts-day]\")],\n});\n\nconst all = () => {\n  const { alerts, emptyState, legends } = getRelevantDOMNodes();\n\n  // Display all alerts\n  alerts.forEach((node) => {\n    node.classList.remove(\"display-none\");\n  });\n\n  // Display all relevant alert map legends\n  legends.forEach((node) => node.classList.remove(\"display-none\"));\n\n  // Hide all empty state text except for day 0.\n  emptyState.forEach((node) => {\n    if (node.dataset.noAlertsDay === \"0\") {\n      node.classList.remove(\"display-none\");\n    } else {\n      node.classList.add(\"display-none\");\n    }\n  });\n};\n\nconst specificDay = (day, dayLevels) => {\n  const { alerts, emptyState, legends } = getRelevantDOMNodes();\n\n  // Start by hiding everything\n  alerts.forEach((node) => {\n    node.classList.add(\"display-none\");\n  });\n  legends.forEach((node) => node.classList.add(\"display-none\"));\n\n  // And then un-hide the relevant alerts.\n  const dayAlerts = [...document.querySelectorAll(`[data-alert-day-${day}]`)];\n  dayAlerts.forEach((node) => node.classList.remove(\"display-none\"));\n\n  // As well as alert map legends that are appropriate for the day.\n  legends.forEach((node) => {\n    if (dayLevels.includes(node.dataset.alertMapLegendLevel)) {\n      node.classList.remove(\"display-none\");\n    }\n  });\n\n  // Hide all empty state text except the relevant day.\n  emptyState.forEach((node) => {\n    if (node.dataset.noAlertsDay === day) {\n      node.classList.remove(\"display-none\");\n    } else {\n      node.classList.add(\"display-none\");\n    }\n  });\n};\n\nwindow.addEventListener(\"wx-tab-focused\", (e) => {\n  const day = e.detail?.dataset?.alertDay;\n\n  // \"All\" is a special case.\n  if (day === \"all\") {\n    all();\n  }\n  // Otherwise, we just want to make sure we have a value. If we don't, then\n  // we didn't get here from focusing a county alert tab, and we don't need\n  // to do anything else. Huzzah!\n  else if (day) {\n    const dayLevels =\n      e.detail?.dataset?.alertLevels\n        ?.split(\" \")\n        .filter((i) => i.trim().length > 0) ?? [];\n\n    specificDay(day, dayLevels);\n  }\n});\n", "/** True when a geometry has points on both sides of the antimeridian. */\nconst crossesAntimeridian = ({ coordinates }) => {\n  let east = false;\n  let west = false;\n\n  const walk = (coords) => {\n    if (typeof coords[0] === \"number\") {\n      east ||= coords[0] > 150;\n      west ||= coords[0] < -150;\n      return;\n    }\n    coords.forEach(walk);\n  };\n  walk(coordinates);\n\n  return east && west;\n};\n\n/** Move points east of the antimeridian west of -180 so the shape draws as one piece. */\nconst shiftAntimeridian = (geometry) => {\n  const wrapPoint = (coord) => {\n    let lng = coord[0];\n    if (lng > 0) lng -= 360; // Shift Aleutians to -180...-190 range\n    return [lng, coord[1]];\n  };\n\n  // Define the recursion to handle Polygon vs MultiPolygon coordinates\n  const transformCoords = (coords) => {\n    if (typeof coords[0] === \"number\") {\n      return wrapPoint(coords);\n    }\n    return coords.map(transformCoords);\n  };\n\n  if (geometry.coordinates) {\n    geometry.coordinates = transformCoords(geometry.coordinates);\n  }\n};\n\n/** Move the Aleutians west of -180 so Alaska draws as one piece. */\nexport const shiftAleutians = (boundary, alerts = []) => {\n  // Only a boundary straddling the antimeridian needs it, and its alerts ride along\n  if (!boundary?.coordinates || !crossesAntimeridian(boundary)) {\n    return;\n  }\n\n  // Process Boundary (it's a Geometry object)\n  shiftAntimeridian(boundary);\n\n  // Process Alerts\n  alerts.forEach((alert) => {\n    if (alert.geometry) {\n      shiftAntimeridian(alert.geometry);\n    }\n  });\n};\n\nconst ESRI_API_KEY =\n  \"AAPK1dd93729edc54e84ade1ea5dc0f4f9d3EPexfd5qirlO3QtHGBj5JQL7iUYHQOb4yLjfKEYFLcyN9PlMd87lMjjv8D3DxDsQ\";\n\n/** Hide the alert map and show the non-critical map error in its place. */\nexport const showMapError = (elementId) => {\n  document\n    .getElementById(\"wx-alert-map-error\")\n    .classList.remove(\"display-none\");\n  document\n    .getElementById(elementId)\n    .closest(\"wx-alert-map, wx-wfo-map\").style.display = \"none\";\n};\n\n/** Put a Leaflet map on the Esri streets basemap. */\nexport const createBaseMap = (elementId, options) => {\n  const L = window.L;\n  const map = L.map(elementId, options).setView([0, 0], 0);\n\n  // Leaflet is managed by a Ukrainian team. The default attribution they put on\n  // maps includes a Ukrainian flag to show their national pride. But as an\n  // official website of the US Government, that might not be appropriate for\n  // us, so we remove the flag.\n  map.attributionControl.setPrefix(\n    \"<a href='https://leafletjs.com' title='A JavaScript library for interactive maps'>Leaflet</a>\",\n  );\n\n  // Add Esri Basemap\n  L.esri.Vector.vectorBasemapLayer(\"arcgis/streets\", {\n    apiKey: ESRI_API_KEY,\n  }).addTo(map);\n\n  return map;\n};\n", "import { createBaseMap, shiftAleutians } from \"./map.js\";\n\nconst ICON_URLS = {\n  warning: \"/public/images/weather/wx_alerticon_circle_warning.svg\",\n  watch: \"/public/images/weather/wx_alerticon_circle_watch.svg\",\n  other: \"/public/images/weather/wx_alerticon_circle_other.svg\",\n};\n\nconst CLUSTER_PRIORITIES = [\"other\", \"watch\", \"warning\"];\n\nconst styles = {\n  outline: {\n    color: \"#11181D\",\n    weight: 3,\n    opacity: 1,\n    fillOpacity: 0,\n    dashArray: \"1 4\",\n    lineCap: \"round\",\n  },\n  warning: {\n    fillColor: \"#D83933\",\n    color: \"#FB5A47\",\n    opacity: 0.85,\n    fillOpacity: 0.3,\n  },\n  watch: {\n    fillColor: \"#D2B93B\",\n    color: \"#947100\",\n    opacity: 0.85,\n    fillOpacity: 0.3,\n  },\n  other: {\n    fillColor: \"#B4C1CD\",\n    color: \"#585E63\",\n    opacity: 0.85,\n    fillOpacity: 0.3,\n  },\n  active: {\n    fillOpacity: 0.5,\n  },\n  hover: {\n    fillOpacity: 0.7,\n    opacity: 1.0,\n    weight: 7,\n  },\n};\n\n/** Render an outline plus clustered, day-filtered alerts on the Esri basemap. */\nexport const createAlertMap = ({\n  elementId,\n  name,\n  maxZoom,\n  outline,\n  alerts,\n  autoPan,\n  onExpandToggle,\n}) => {\n  const L = window.L;\n  const polylabel = window.polylabel;\n  const layersByDay = { 1: [], 2: [], 3: [], 4: [], 5: [], all: [] };\n  let curDayIndex = \"all\";\n\n  const activeLayers = () => layersByDay[curDayIndex] ?? [];\n\n  shiftAleutians(outline, alerts);\n\n  const map = createBaseMap(elementId, {\n    zoomDelta: 1,\n    zoomSnap: 0.5,\n    maxZoom,\n  });\n\n  /** A custom expand/shrink button for the map container. */\n  const ExpandControl = L.Control.extend({\n    options: {\n      position: \"topright\",\n    },\n\n    onAdd: function (map) {\n      this.map = map;\n      this.container = map.getContainer().parentElement;\n      this.button = document.createElement(\"button\");\n      this.button.classList.add(\"wx-radar-expand\", \"padding-0\", \"margin-1\");\n      this.buttonSetToExpand();\n      this.button.addEventListener(\"click\", this._resize.bind(this));\n      return this.button;\n    },\n\n    buttonSetToExpand: function () {\n      this.button.innerHTML = `<svg role=\"img\" aria-hidden=\"true\" class=\"width-full height-full\"><use xlink:href=\"/public/images/uswds/sprite.svg#zoom_out_map\"></use></svg>`;\n      this.button.setAttribute(\"aria-label\", `Expand the ${name} alert map`);\n    },\n\n    buttonSetToCollapse: function () {\n      this.button.innerHTML = `<svg role=\"img\" aria-hidden=\"true\" class=\"width-full height-full\"><use xlink:href=\"/public/images/spritesheet.svg#wx_zoom-in-map\"></use></svg>`;\n      this.button.setAttribute(\"aria-label\", `Collapse the ${name} alert map`);\n    },\n\n    _resize: function () {\n      onExpandToggle(this.container);\n      this.button.classList.toggle(\"wx-map-control__expanded\");\n      if (this.button.classList.contains(\"wx-map-control__expanded\")) {\n        this.buttonSetToCollapse();\n      } else {\n        this.buttonSetToExpand();\n      }\n\n      // Critical for Leaflet to recalculate the canvas size\n      this.map.invalidateSize();\n    },\n\n    onRemove: function () {\n      // noop\n    },\n  });\n  new ExpandControl().addTo(map);\n\n  // Styles and icons\n  const MapIcon = L.Icon.extend({\n    options: {\n      iconSize: [32, 32],\n      iconAnchor: [16, 16],\n      popupAnchor: [0, -8],\n    },\n  });\n\n  const icons = {\n    warning: new MapIcon({ iconUrl: ICON_URLS.warning }),\n    watch: new MapIcon({ iconUrl: ICON_URLS.watch }),\n    other: new MapIcon({ iconUrl: ICON_URLS.other }),\n  };\n\n  const getLargeIcon = (type) =>\n    new MapIcon({\n      iconUrl: ICON_URLS[type],\n      iconSize: [40, 40],\n      iconAnchor: [20, 20],\n      popupAnchor: [0, -10],\n    });\n\n  /** Convert a map's bounds in lat/lng to x/y. */\n  const getXYBounds = () => {\n    const latlngBounds = map.getBounds();\n    const southeast = latlngBounds.getSouthEast();\n    const northwest = latlngBounds.getNorthWest();\n    return L.bounds(\n      [northwest.lat, northwest.lng],\n      [southeast.lat, southeast.lng],\n    );\n  };\n\n  /** Determine the center of a layer, considering only points within the viewport. */\n  const visibleCenter = (layer, xybounds) => {\n    const { geometry } = layer.getLayers()[0].feature;\n\n    // If it's a Polygon, we wrap it in an array to treat it like a MultiPolygon with one item\n    const polygonList =\n      geometry.type === \"MultiPolygon\"\n        ? geometry.coordinates\n        : [geometry.coordinates];\n\n    // Loop through list of polygons\n    // When finding the center, return center\n    for (const polygonCoords of polygonList) {\n      // Get Center of polygon using polylabel (center of mass)\n      const [lng, lat] = polylabel(polygonCoords, 0.000001);\n      const labelCenter = L.latLng(lat, lng);\n\n      // If the natural center of this polygon is visible, return\n      if (map.getBounds().contains(labelCenter)) {\n        return labelCenter;\n      }\n\n      // If natural center isn't visible, the polygon might still be partially on screen\n      const points = polygonCoords[0].map(([lng, lat]) => L.point([lat, lng]));\n\n      // Clip polygon within viewport (`xybounds`)\n      const clippedPoints = L.PolyUtil.clipPolygon(points, xybounds);\n\n      if (clippedPoints.length > 0) {\n        // Convert clipped xy points back to LatLngs for polygonCenter\n        const clippedLatLngs = clippedPoints.map((p) => L.latLng([p.x, p.y]));\n        try {\n          return L.PolyUtil.polygonCenter(clippedLatLngs, map.options.crs);\n        } catch {\n          // Fallback if polygonCenter fails on weird clipped shapes\n        }\n      }\n    }\n\n    // If no part of any polygon is within the viewport\n    return null;\n  };\n\n  /** Change the opacity of the selected alert. */\n  const handleMarkerEvent = (e, layer) => {\n    switch (e.type) {\n      case \"click\":\n        layer.setStyle(styles.active);\n        break;\n      case \"popupclose\":\n      case \"mouseout\":\n        layer.resetStyle();\n        break;\n      case \"mouseover\":\n        layer.setStyle(styles.hover);\n        break;\n      default:\n        break;\n    }\n  };\n\n  /** Marker Clusters for alert Icons **/\n  const markers = L.markerClusterGroup({\n    showCoverageOnHover: false,\n\n    // Cluster marker Icon rendering function, icon defaults to highest alert clustered\n    iconCreateFunction: (cluster) => {\n      const highest = Math.max(\n        ...cluster\n          .getAllChildMarkers()\n          .map((marker) => CLUSTER_PRIORITIES.indexOf(marker.alert_type)),\n      );\n      const type = CLUSTER_PRIORITIES[highest] ?? \"other\";\n      const count = cluster.getChildCount();\n\n      return L.divIcon({\n        html: `\n          <div class=\"alert-cluster-badge-container\" title=\"${count} ${type} alerts\">\n            <img src=\"${ICON_URLS[type]}\" class=\"alert-cluster-main-icon\" alt=\"\" />\n            <div class=\"alert-cluster-badge alert-badge-${type}\" aria-hidden=\"true\">\n              ${count}\n            </div>\n          </div>\n        `,\n        className: \"leaflet-cluster-icon\",\n        iconSize: [40, 40],\n        iconAnchor: [20, 20],\n      });\n    },\n  });\n\n  /** Marker Cluster event functions  **/\n  markers.on(\"spiderfied\", (e) => {\n    if (e.cluster._icon) {\n      // When cluster is spiderfied, it needs to be invisible\n      e.cluster._icon.style.opacity = \"0\";\n      e.cluster._icon.style.pointerEvents = \"none\";\n    }\n  });\n\n  markers.on(\"unspiderfied\", (e) => {\n    if (e.cluster._icon) {\n      // When cluster is unspiderfied, it needs to be visible\n      e.cluster._icon.style.opacity = \"1\";\n      e.cluster._icon.style.pointerEvents = \"auto\";\n    }\n  });\n\n  // zoom to the outline (but do not draw it yet)\n  const outlineLayer = L.geoJSON(outline, { style: styles.outline });\n  map.fitBounds(outlineLayer.getBounds(), { padding: [15, 15] });\n  const outlineXYBounds = getXYBounds();\n  const outlineZoom = map.getZoom();\n  let latestZoom = outlineZoom;\n\n  /** Restacks all active alert polygons reversed, based on their initial render index. */\n  const restackAlerts = () => {\n    [...activeLayers()]\n      .sort((a, b) => b.wx_render_index - a.wx_render_index)\n      .forEach((layer) => {\n        if (map.hasLayer(layer)) {\n          layer.bringToFront();\n        }\n      });\n\n    // Bring the outline to the front at the end\n    outlineLayer.bringToFront();\n  };\n\n  /** Redraw icons on zoom in or pan; reset them on zoom out. */\n  const handleMotion = (e) => {\n    // Reset style when moved\n    activeLayers().forEach((layer) => layer.resetStyle());\n\n    const zoom = e.target.getZoom();\n    if (zoom <= outlineZoom && latestZoom > outlineZoom) {\n      activeLayers().forEach((layer) => {\n        layer.wx_marker.setLatLng(layer.wx_marker.wx_orig_pos);\n      });\n    } else {\n      const xybounds = getXYBounds();\n      activeLayers().forEach((layer) => {\n        // Fix visible center can be null if the polygon isn't in viewport. if null, skip\n        const center = visibleCenter(layer, xybounds);\n        if (center) {\n          layer.wx_marker.setLatLng(center);\n        }\n      });\n    }\n    latestZoom = zoom;\n\n    // Only refresh if marker cluster is full\n    if (markers.getLayers().length > 0) {\n      try {\n        markers.refreshClusters();\n      } catch (err) {\n        console.warn(\"MarkerCluster refresh suppressed during motion:\", err);\n      }\n    }\n  };\n\n  map.on(\"zoomend\", handleMotion);\n  map.on(\"moveend\", handleMotion);\n\n  /** Show alerts for the selected day or for \"all\". */\n  const filterMap = () => {\n    // If we aren't viewing \"all\", hide the \"all\" layers first\n    if (curDayIndex !== \"all\") {\n      layersByDay.all.forEach((layer) => {\n        layer.setStyle({ fillOpacity: 0, opacity: 0 });\n        layer.wx_marker.remove();\n      });\n    }\n\n    // Remove existing markers\n    markers.clearLayers();\n    activeLayers().forEach((layer) => {\n      layer.resetStyle();\n      markers.addLayer(layer.wx_marker);\n    });\n\n    if (markers.getLayers().length > 0) {\n      markers.refreshClusters();\n    }\n  };\n\n  // Empty map { alertId: layer } for hovering over alert accordian\n  const alertIdToLayer = {};\n\n  // Highlight function for mouseover events\n  const highlightAlert = (alertId) => {\n    const layer = alertIdToLayer[alertId];\n    if (!layer) return;\n\n    const marker = layer.wx_marker;\n\n    // Update Marker icon and z-index\n    marker.setIcon(getLargeIcon(marker.alert_type));\n    marker._icon?.classList.add(\"alert-marker-mouseover\");\n    marker.setZIndexOffset(100000);\n    layer.bringToFront();\n\n    // Set hover style\n    layer.setStyle(styles.hover);\n  };\n\n  // Highlight function for mouseout events\n  const unhighlightAlert = (alertId) => {\n    const layer = alertIdToLayer[alertId];\n    if (!layer) return;\n\n    const marker = layer.wx_marker;\n\n    // Reset Marker\n    marker.setIcon(icons[marker.alert_type]);\n    marker._icon?.classList.remove(\"alert-marker-mouseover\");\n    marker.setZIndexOffset(0);\n\n    // Reset Visual Style\n    layer.resetStyle();\n\n    // Place layer back in it's original order\n    restackAlerts();\n  };\n\n  // List for storing alert labels\n  const markerList = [];\n\n  // create alert layers and sort them\n  for (let i = alerts.length - 1; i >= 0; i--) {\n    const { id, type, geometry, days, popup } = alerts[i];\n    if (!geometry) continue;\n\n    try {\n      const layer = L.geoJSON(geometry, { style: styles[type] }).addTo(map);\n      const center = visibleCenter(layer, outlineXYBounds);\n\n      // Store the render index for sorting during highlight events\n      layer.wx_render_index = i;\n\n      layer.wx_marker = L.marker(center, { icon: icons[type] });\n      layer.wx_marker.alert_type = type;\n      layer.wx_marker.wx_orig_pos = center;\n      layer.wx_marker.bindPopup(popup, { autoPan });\n      layer.wx_marker.on(\"click\", (e) => handleMarkerEvent(e, layer));\n      layer.wx_marker.on(\"popupclose\", (e) => handleMarkerEvent(e, layer));\n      layer.wx_marker.on(\"mouseover\", () => highlightAlert(id));\n      layer.wx_marker.on(\"mouseout\", () => unhighlightAlert(id));\n\n      alertIdToLayer[id] = layer;\n\n      // Add marker to list\n      markerList.push(layer.wx_marker);\n\n      days.forEach((day) => layersByDay[day]?.push(layer));\n      layersByDay.all.push(layer);\n    } catch (error) {\n      console.error(`Could not draw alert ${id}`, error);\n    }\n  }\n\n  // Add cluster markers\n  markers.addLayers(markerList);\n  map.addLayer(markers);\n\n  // day selection starts on \"all\", but the user might have changed it\n  const selected = document.querySelector(\n    \"wx-tabs button[aria-selected='true']\",\n  );\n  curDayIndex = selected?.dataset.alertDay ?? \"all\";\n\n  outlineLayer.addTo(map);\n  filterMap();\n\n  // ready to handle day change events, other wx-tabs on the page don't carry an alert day\n  window.addEventListener(\"wx-tab-focused\", (e) => {\n    const day = e.detail.dataset.alertDay;\n    if (day) {\n      curDayIndex = day;\n      filterMap();\n    }\n  });\n\n  return { map, highlightAlert, unhighlightAlert };\n};\n", "/** Fetch a Geobuf endpoint as an arraybuffer, rejecting on a non-2xx response. */\nexport const fetchGeobuf = (url) =>\n  fetch(url).then((res) => {\n    if (!res.ok) {\n      throw new Error(`${url} responded with ${res.status}`);\n    }\n    return res.arrayBuffer();\n  });\n\n/** Decode a Geobuf arraybuffer back into GeoJSON. */\nexport const decodeGeobuf = (buffer) => {\n  const geojson = window.geobuf.decode(new window.Pbf(buffer));\n  // An empty FeatureCollection encodes without a feature_collection field and decodes to {}\n  return geojson.type ? geojson : { type: \"FeatureCollection\", features: [] };\n};\n", "export const checkForLeaflet = (callback) => {\n  if (window.L && window.L.esri && window.L.esri.Vector) {\n    callback();\n  } else {\n    // DOMContentLoaded fires after every deferred script, the Leaflet plugins and geobuf included\n    document.addEventListener(\"DOMContentLoaded\", callback, { once: true });\n  }\n};\n", "import { createAlertMap } from \"./alertMap.js\";\nimport { decodeGeobuf, fetchGeobuf } from \"./geobuf.js\";\nimport { showMapError } from \"./map.js\";\nimport { checkForLeaflet } from \"./util.js\";\n\nconst MAP_ID = \"wx_county_alert_map\";\n\nconst meta = JSON.parse(document.getElementById(\"county-metadata\").textContent);\n\n// Kick off at module load so the fetches overlap the Leaflet script load\nconst geobufRequests = meta.isBinary\n  ? Promise.all([\n      fetchGeobuf(`/wx/county/${meta.countyFips}/`),\n      fetchGeobuf(`/wx/county/${meta.countyFips}/alerts`),\n    ])\n  : null;\n\n/** Put the geometry the view stripped back where the page data expects it. */\nconst hydrateGeometry = async (json) => {\n  const [boundaryBuf, alertsBuf] = await geobufRequests;\n  json.county.shape = decodeGeobuf(boundaryBuf);\n\n  const geometries = new Map(\n    decodeGeobuf(alertsBuf).features.map((feature) => [\n      feature.properties.id,\n      feature.geometry,\n    ]),\n  );\n  json.alerts.items.forEach((item) => {\n    item.geometry = geometries.get(item.id) ?? item.geometry;\n  });\n};\n\n/** Open the associated alert accordion and bring it into view. */\nconst handlePopupClick = (e) => {\n  const accordion = document.querySelector(\n    `button[aria-controls='a${e.target.dataset.alert_id}']`,\n  );\n  accordion.focus();\n  accordion.scrollIntoView({ behavior: \"smooth\" });\n  if (accordion.getAttribute(\"aria-expanded\", \"\") === \"false\")\n    accordion.click();\n};\n\n/** HTML shown inside a popup when clicking on an alert icon on the map. */\nconst getPopupHTML = (alertId, alertName) => {\n  const html = document.createElement(\"div\");\n  html.classList.add(\"text-center\");\n  html.innerHTML = `\n    <div class=\"font-body-xs margin-bottom-2px\">${gettext(alertName)}</div>\n    <div>\n      <button class=\"usa-button usa-button--unstyled font-body-xs\" type=\"button\">\n        ${gettext(\"js.alerts.link.see-details.01\")}\n      </button>\n    </div>\n  `;\n  const btn = html.querySelector(\"button\");\n  btn.addEventListener(\"click\", handlePopupClick);\n  btn.dataset.alert_id = alertId;\n  return html;\n};\n\n/** Add the user's location if they've already agreed to share it. */\nconst showUserLocation = async (map) => {\n  try {\n    const result = await navigator.permissions.query({ name: \"geolocation\" });\n    if (result.state === \"granted\") {\n      navigator.geolocation.getCurrentPosition((position) => {\n        const locationIcon = window.L.divIcon({\n          className: \"wx-location-marker\",\n        });\n        window.L.marker([position.coords.latitude, position.coords.longitude], {\n          icon: locationIcon,\n          interactive: false,\n        }).addTo(map);\n        // Hide the location marker from screen readers and remove it from the tab\n        // order. It's not interactive, so there's no reason it should be focusable.\n        const locationMarker = document.querySelector(\n          \".leaflet-marker-icon.wx-location-marker\",\n        );\n        locationMarker?.setAttribute(\"aria-hidden\", \"true\");\n        locationMarker?.setAttribute(\"tabindex\", \"-1\");\n      });\n    }\n  } catch (error) {\n    console.log(error);\n  }\n};\n\n/** Initialize county alert map after Leaflet has loaded. */\nconst setupMap = async () => {\n  try {\n    const json = JSON.parse(document.getElementById(\"county-data\").textContent);\n    if (meta.isBinary) {\n      await hydrateGeometry(json);\n    }\n\n    const { map, highlightAlert, unhighlightAlert } = createAlertMap({\n      elementId: MAP_ID,\n      name: \"county\",\n      maxZoom: 18,\n      outline: json.county.shape,\n      autoPan: false,\n      onExpandToggle: (container) => {\n        container.parentElement.classList.toggle(\"tablet:grid-col-7\");\n        container.classList.toggle(\"wx-county-alert-map-container__expanded\");\n      },\n      alerts: json.alerts.items.map((item) => ({\n        id: item.unique_id,\n        type: item.metadata.level.text,\n        geometry: item.geometry,\n        days: item.alertDays,\n        popup: getPopupHTML(item.unique_id, item.event),\n      })),\n    });\n\n    // Hover alert accordion logic\n    document.querySelectorAll(\".usa-accordion\").forEach((item) => {\n      const alertId = item.id.replace(\"alert_\", \"\");\n      item.addEventListener(\"mouseover\", () => highlightAlert(alertId));\n      item.addEventListener(\"mouseout\", () => unhighlightAlert(alertId));\n    });\n\n    showUserLocation(map);\n  } catch (error) {\n    console.error(\"Error loading county map data:\", error);\n    showMapError(MAP_ID);\n  }\n};\n\ncheckForLeaflet(setupMap);\n", "const toggleMapExpand = (() => {\n  let expanded = false;\n\n  const sprites = {\n    false: \"/public/images/uswds/sprite.svg#zoom_out_map\",\n    true: \"/public/images/spritesheet.svg#wx_zoom-in-map\",\n  };\n\n  return (event) => {\n    const container = event.target.closest(\".wx-radar-container\");\n    const wrapper = event.target.closest(\".wx-radar-wrapper\");\n    const svgUse = container.querySelector(\"button.wx-radar-expand svg use\");\n    const isLargeMap = container.classList.contains(\"wx-large-map\");\n\n    expanded = !expanded;\n\n    if (expanded) {\n      container.classList.add(\"wx-radar-container__expanded\");\n    } else {\n      container.classList.remove(\"wx-radar-container__expanded\");\n    }\n\n    // on small maps, the expand button widens the map; on large maps,\n    // (like state) the expand button changes the aspect ratio (via CSS)\n    if (!isLargeMap) {\n      if (expanded) {\n        wrapper.classList.remove(\"desktop:grid-col-6\");\n        wrapper.classList.add(\"desktop:grid-col-12\");\n      } else {\n        wrapper.classList.add(\"desktop:grid-col-6\");\n        wrapper.classList.remove(\"desktop:grid-col-12\");\n      }\n    }\n\n    const descriptors = Array.from(\n      container.querySelectorAll(\".wx-radar-expand__description\"),\n    );\n    for (const descriptor of descriptors) {\n      if (descriptor.classList.contains(\"display-none\")) {\n        descriptor.classList.remove(\"display-none\");\n      } else {\n        descriptor.classList.add(\"display-none\");\n      }\n    }\n\n    svgUse.setAttribute(\"xlink:href\", sprites[expanded]);\n\n    // If an element changes size due toggling a CSS class, that does not\n    // trigger a resize event. CMI is listening to resize events on the window,\n    // so let's fire a resize event so the map will grow/shrink correctly.\n    window.dispatchEvent(new Event(\"resize\"));\n  };\n})();\n\nconst updateRadarTimestamps = async (container) => {\n  const timezone = container.getAttribute(\"data-timezone\") || \"UTC\";\n\n  try {\n    const response = await fetch(\n      \"https://opengeo.ncep.noaa.gov/geoserver/conus/conus_bref_qcd/ows?service=wms&version=1.1.1&request=GetCapabilities\",\n    );\n    const text = await response.text();\n\n    // It's XML. Yay. Anyway, all of the times are listed as a single long\n    // string, separated by commas. The most recent is at the end. CMI only\n    // uses 20 frames, so we extract the last 20 timestamps.\n    const match = text.match(/<Extent name=\"time\".*>(.+)<\\/Extent>/);\n\n    if (match) {\n      const [, times] = match;\n      const range = times.split(\",\").slice(-20);\n      const start = new Date(range[0]);\n      const end = new Date(range.pop());\n\n      const formatOptions = {\n        hour: \"numeric\",\n        minute: \"2-digit\",\n        timeZone: timezone,\n        timeZoneName: \"short\",\n      };\n\n      const startFormatter = new Intl.DateTimeFormat(\"en-US\", {\n        ...formatOptions,\n        weekday: \"long\",\n      });\n      const endFormatter = new Intl.DateTimeFormat(\"en-US\", formatOptions);\n\n      const label = container\n        .closest(\"[wx-outer-radar-container]\")\n        ?.querySelector(\"#wx-radar-timestamp-label\");\n      if (label) {\n        label.innerText = `${startFormatter.format(start)} \u2013 ${endFormatter.format(end)}`;\n      }\n    }\n  } catch (e) {\n    // Fail silently\n  }\n};\n\nconst setupRadar = () => {\n  // Point pages may contain a radar in both Today and Maps. Only initialize\n  // the one in the visible tab; the other may not have arrived yet via HTMX.\n  const activeTab = document.querySelector(\n    \"#point-page-tabbed-nav .wx-tab-container[data-selected]\",\n  );\n  const scope = activeTab || document;\n\n  // If radar has already been initialized on the container\n  // element, return and do nothing else.\n  const existingRadar = scope.querySelector(\".cmi-radar-container\");\n  if (existingRadar) {\n    return;\n  }\n\n  const container = scope.querySelector(\"wx-radar\");\n  if (!container) {\n    return;\n  }\n\n  updateRadarTimestamps(container);\n\n  const bookmark = {\n    agenda: {\n      id: \"weather\",\n    },\n    opacity: {\n      alerts: 0,\n    },\n  };\n\n  const bounds = container.getAttribute(\"bounds\");\n  if (bounds) {\n    try {\n      const boundingCoordinates = JSON.parse(bounds);\n      bookmark.agenda = {\n        custom: {\n          id: \"radar\",\n          layers: [\"activearea\", \"national\"],\n          area: {\n            fitMaxZoom: 20,\n            fitPadding: [85, 85, 85, 85],\n            polygon: boundingCoordinates,\n            style: {\n              stroke: { color: \"transparent\" },\n              fill: { color: \"transparent\" },\n            },\n          },\n        },\n      };\n      bookmark.menudis = false;\n    } catch (e) {\n      console.error(`Could not parse bounds for radar geometry`);\n      return;\n    }\n  } else {\n    const lat = Number.parseFloat(container.getAttribute(\"lat\"));\n    const lon = Number.parseFloat(container.getAttribute(\"lon\"));\n\n    const point = [lon, lat];\n    bookmark.agenda = {\n      id: \"weather\",\n      zoom: 7,\n      center: point,\n      location: point,\n    };\n    bookmark.menudis = false;\n  }\n\n  const options = {\n    settings: {\n      bookmark: `v1_${btoa(JSON.stringify(bookmark))}`,\n      quickset: null,\n    },\n    urls: {\n      alerts: \"https://alerts.weather.gov\",\n      api: \"https://api.weather.gov\",\n      forecast: \"https://forecast.weather.gov\",\n      gis: \"https://opengeo.ncep.noaa.gov/geoserver\",\n    },\n    // We'll explicitly set the ESRI key here, so it's easier to change if we\n    // need to in the future. Rather than patching the CMI library, we can just\n    // update this.\n    esriKey:\n      \"AAPTxy8BH1VEsoebNVZXo8HurNPcJD0FIYgRqKcG6xxTBL9nh-VFBFPksbJUeCAaOBmIl7l_u3FU4qHnugzOvbnCvb7RMvR4FD_D4AhbAn2hMpcV-vKc8Oz6Kb0itTkdvSjaBCv5EHG20BLTk7jV0VSlPq_N9FhOT2bn2z510HsHPTf4N2TkszfZwmZgzRYHS06-OFp40ixlJ2vLLRK8a_L_ojVp3FXtRCXPNFWXFKQzYdiNzx12uaMvJ_riiEvC7vfrAT1_JWn0gzIT\",\n  };\n\n  const target = activeTab\n    ? `#${activeTab.id} #wx-radar-container`\n    : \"#wx-radar-container\";\n  window.app = window.cmiRadar.createApp(target, options);\n\n  // update the radar external link.\n  const link = scope.querySelector(\"#radar-point-link\");\n  if (link) {\n    link.href = `https://radar.weather.gov/?settings=${options.settings.bookmark}`;\n  }\n\n  [\".cmi-radar-container .menu\", \".cmi-radar-menu-agendas\"].forEach(\n    (selector) => {\n      const element = scope.querySelector(selector);\n      if (element) {\n        element.remove();\n      }\n    },\n  );\n\n  const expandButton = scope.querySelector(\"button.wx-radar-expand\");\n  if (expandButton) {\n    expandButton.addEventListener(\"click\", toggleMapExpand);\n\n    // The sticky top of the expand button should be the bottom of the tab list,\n    // so query that and set the button's top accordingly. Do it this way rather\n    // than hard-coding it so things will behave well later if the tab list\n    // height changes.\n    const tabList = document.querySelector(`div.tab-buttons[role=\"tablist\"]`);\n    if (tabList) {\n      const buttonContainer = expandButton.parentElement;\n      buttonContainer.style.top = `${tabList.offsetHeight}px`;\n    }\n  }\n\n  window.addEventListener(\"wx-auto-update\", (e) => {\n    if (e?.detail?.target === \"radar\") {\n      updateRadarTimestamps(container);\n    }\n  });\n\n  // When the radar auto-refreshes and gets new frames, we\n  // need to update the timestamps. Hook into the cmi-radar's\n  // events for when new frames come in, then call the timestamp\n  // update function.\n  window.app.$store.watch(\n    () => window.app.$store.getters.animationFramesRaw,\n    (newFrames) => {\n      // If frames is an array, the frames have loaded even if invalid or empty\n      if (Array.isArray(newFrames)) {\n        if (newFrames.length > 0) {\n          // Then we have received new radar frames\n          // So let's update the timestamps\n          updateRadarTimestamps(container);\n        } else {\n          console.warn(\"RADAR-FRAMES-LISTENER: Invalid frames received\");\n        }\n      }\n    },\n    { immediate: true },\n  );\n};\n\nconst scriptEl = document.querySelector(\"[data-wx-radar-cmi]\");\nconst currentTabSelected = document.querySelector(\n  \"#today[data-selected], #maps[data-selected]\",\n);\nconst radarEnabled = document.querySelector(\"#radar-enable\");\n\nconst trySetupRadar = () => {\n  if (window.cmiRadar) {\n    setupRadar();\n  }\n};\n\nif (currentTabSelected || radarEnabled) {\n  trySetupRadar();\n}\n\nscriptEl?.addEventListener(\"load\", trySetupRadar);\ndocument.addEventListener(\"wx:tab-switched\", (event) => {\n  if (event.detail.tabId === \"today\" || event.detail.tabId === \"maps\") {\n    trySetupRadar();\n  }\n});\ndocument.addEventListener(\"wx:tab-content-loaded\", (event) => {\n  if (event.detail.tabId === \"today\" || event.detail.tabId === \"maps\") {\n    trySetupRadar();\n  }\n});\n"],
  "mappings": "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",
  "names": ["Timer", "callback", "delay", "TabbedNavigator", "pointTablist", "tab", "alertAnchor", "button", "tablist", "maxScroll", "hash", "matchedTabButton", "childElement", "tabContainer", "tabId", "element", "tabButton", "event", "currentPath", "matchingTab", "anchorEl", "accordionEl", "accordionElement", "on", "content", "currentElement", "isFirst", "isLast", "accordionTop", "buttonAreaHeight", "scrollY", "setupSiteSearchMenuButton", "siteSubmenuElement", "button", "siteSearchSubmenu", "mobileButton", "tabletButton", "footerRegion", "prefersReducedMotion", "scrollBracket", "bottomY", "hideThreshold", "minScrollThreshold", "hideThreshold", "minScrollThreshold", "scrollBracket", "bottomY", "mobileButton", "tabletButton", "scrollUp", "prefersReducedMotion", "Listbox", "e", "selected", "first", "event", "closestOption", "handler", "host", "option", "idx", "element", "fireEvent", "selectedEl", "current", "options", "currentIndex", "prev", "firstOption", "lastOption", "next", "navigateToElement", "combobox", "popup", "selected", "targetUrl", "sections", "navLinks", "observerOptions", "observerCallback", "entries", "entry", "id", "link", "activeLink", "observer", "section", "hideNavigationLoader", "loader", "showNavigationLoader", "event", "loaders", "activeNav", "text", "goToLocationPage", "latitude", "longitude", "form", "removeBrowserLocationButtons", "buttons", "button", "sibling", "shouldPrompt", "status", "buttonHandler", "e", "proceed", "text", "lat", "long", "code", "message", "alertText", "comboTemplate", "Combobox", "target", "event", "name", "assigned", "value", "id", "element", "popupIsOpen", "handler", "clearButton", "oldVal", "newVal", "RECENT_LOC_STORAGE", "getRecentLocations", "existing", "parsed", "url", "updated", "rest", "addRecentLocation", "obj", "sliced", "debouncer", "Timer", "getRedirectUrlFromAddressCandidate", "addressCandidate", "type", "lat", "lon", "abbr", "typeLowercase", "makeListItemFromResultItem", "setSize", "describedby", "suggestion", "idx", "item", "makeListFromResult", "resultListElement", "ariaDescEl", "suggestions", "newItems", "LocationListbox", "Listbox", "addRecentLocation", "element", "selectItemPromise", "resolve", "form", "geoData", "formUrl", "event", "key", "filterTerm", "savedSearchesGroup", "savedSearchesLabel", "saved", "getRecentLocations", "match", "option", "text", "response", "numResults", "translation", "transWithCount", "data", "headerElement", "magicKey", "result", "cached", "url", "results", "firstCandidate", "x", "y", "SAVED_LOC_STORAGE", "TAB_REGEX", "normalizeLocationUrl", "url", "normalizeSavedLocationStorage", "storage", "text", "location", "getParsedSavedLocationStorage", "SAVED_LOC_STORAGE", "parsedStorage", "setSavedLocationStorage", "newStorage", "getSavedLocations", "current", "addSavedLocation", "obj", "textLower", "existing", "getParsedSavedLocationStorage", "hashed", "sorted", "largerElemIndex", "item", "setSavedLocationStorage", "removeSavedLocation", "loc", "locLower", "existingSorted", "existingHashed", "existingElemIdx", "SavedLocationsSection", "currentLocations", "getSavedLocations", "str", "locations", "listUl", "listColumnClass", "newElems", "index", "text", "url", "element", "cleanedText", "templateLi", "clonedLi", "liButton", "liAnchor", "anchorId", "itemLength", "columnBase", "classRange", "columnPostfix", "btn", "e", "currentTarget", "currentLoc", "currentUrl", "removeSavedLocation", "addSavedLocation", "addLocation", "buttonId", "currentSavedLocations", "currentList", "currentListUl", "currentLocationIndex", "loc", "currentColumnClass", "newColumnClass", "currentLocationItem", "newListItem", "detail", "removeLocation", "getRUMApplicationId", "tag", "config", "createAwsRumClient", "name", "id", "version", "region", "scriptSrc", "p", "scriptTag", "pageGroups", "path", "match", "what", "isUsingHTMX", "getPointForecastPageName", "setupRecording", "event", "rumEventData", "pathname", "pageTags", "pageTypeTag", "pointForecastTabPageName", "APPLICATION_ID", "replaceFetch", "banner", "template", "importantHosts", "maxDelay", "debouncer", "Timer", "metronome", "hideOfflineBanner", "text", "checkOffline", "_", "showOfflineBanner", "wait", "delay", "resolve", "resource", "options", "maxRetries", "tries", "requestedHost", "error", "array", "jitter", "debouncer", "Timer", "text", "updateAriaLive", "e", "delay", "span", "liveRegion", "Accordion", "contentId", "Tabs", "tabElement", "event", "tab", "panelId", "panel", "tabpanelElement", "currentFocus", "firstItemInFocus", "lastItemInFocus", "handled", "anElement", "matchString", "childFocusElement", "getRelevantDOMNodes", "all", "alerts", "emptyState", "legends", "node", "specificDay", "day", "dayLevels", "e", "i", "crossesAntimeridian", "coordinates", "east", "west", "walk", "coords", "shiftAntimeridian", "geometry", "wrapPoint", "coord", "lng", "transformCoords", "shiftAleutians", "boundary", "alerts", "alert", "ESRI_API_KEY", "showMapError", "elementId", "createBaseMap", "options", "L", "map", "ICON_URLS", "CLUSTER_PRIORITIES", "styles", "createAlertMap", "elementId", "name", "maxZoom", "outline", "alerts", "autoPan", "onExpandToggle", "L", "polylabel", "layersByDay", "curDayIndex", "activeLayers", "shiftAleutians", "map", "createBaseMap", "ExpandControl", "MapIcon", "icons", "getLargeIcon", "type", "getXYBounds", "latlngBounds", "southeast", "northwest", "visibleCenter", "layer", "xybounds", "geometry", "polygonList", "polygonCoords", "lng", "lat", "labelCenter", "points", "clippedPoints", "clippedLatLngs", "p", "handleMarkerEvent", "e", "markers", "cluster", "highest", "marker", "count", "outlineLayer", "outlineXYBounds", "outlineZoom", "latestZoom", "restackAlerts", "a", "b", "handleMotion", "zoom", "center", "err", "filterMap", "alertIdToLayer", "highlightAlert", "alertId", "unhighlightAlert", "markerList", "i", "id", "days", "popup", "day", "error", "fetchGeobuf", "url", "res", "decodeGeobuf", "buffer", "geojson", "checkForLeaflet", "callback", "MAP_ID", "meta", "geobufRequests", "fetchGeobuf", "hydrateGeometry", "json", "boundaryBuf", "alertsBuf", "decodeGeobuf", "geometries", "feature", "item", "handlePopupClick", "e", "accordion", "getPopupHTML", "alertId", "alertName", "html", "btn", "showUserLocation", "map", "position", "locationIcon", "locationMarker", "error", "setupMap", "highlightAlert", "unhighlightAlert", "createAlertMap", "container", "showMapError", "checkForLeaflet", "toggleMapExpand", "expanded", "sprites", "event", "container", "wrapper", "svgUse", "isLargeMap", "descriptors", "descriptor", "updateRadarTimestamps", "timezone", "match", "times", "range", "start", "end", "formatOptions", "startFormatter", "endFormatter", "label", "setupRadar", "activeTab", "scope", "bookmark", "bounds", "boundingCoordinates", "lat", "point", "options", "target", "link", "selector", "element", "expandButton", "tabList", "buttonContainer", "e", "newFrames", "scriptEl", "currentTabSelected", "radarEnabled", "trySetupRadar"]
}
