/*prevent FOUC on mobile when using sidebar */
.dwc-mobile :is(.bricks-is-frontend.brx-header-left, .bricks-is-frontend.brx-header-right) #brx-header {
  position: relative;
  inline-size: 100%;
  flex-direction: column;
}

.dwc-mobile .bricks-is-frontend:is(.brx-header-left, .brx-header-right) :is(#brx-content, #brx-footer) {
  margin-inline-start: 0;
}

/*prevent FOUC on desktop when using sidebar */
.bricks-is-frontend:is(.brx-header-left, .brx-header-right):not(.show-nav) #dwc_nav_wrapper {
  display: none;
}

/*=== sidebar css ===*/
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header {
  flex-direction: column;
  box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.7);  
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]).no-scroll {
  overflow: visible;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
  max-block-size: 100dvb;
  padding-block-end: 12rem;
  overscroll-behavior: contain;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc_nav_wrapper {
  position: relative;
  overflow: hidden;
  block-size: 100%;
  transform: translateX(0%);
  visibility: visible;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #dwc-nest-menu .brxe-toggle {
  display: none !important;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu {
  display: flex;
  flex-direction: column;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-header > div {
  display: flex;
  grid-template-columns: 1fr;
  block-size: 100%;
  flex-direction: column;
  justify-content: flex-start;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-menu-wrap {
  inline-size: 100%;
  display: grid;
  grid-template-columns: 1fr;
  block-size: 100%;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header :is(.brxe-code, .dwc-nest-menu-overlay) {
  display: none;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-header {
  inline-size: 100%;
  padding-inline: 0;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #mobile_menu_top {
  min-block-size: var(--top-offset);
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu:not( [data-hide-close-bar = 'true']) .brx-dropdown-content {
  inset-block-start: calc(var(--top-offset) + 1px) !important;

}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu:not( [data-submenu-reveal = 'slide']) .brx-dropdown-content:not([data-submenu-reveal = 'slide'] *) {  
  inset-inline-start: 0;
  inset-block-start: unset !important;
  overflow: hidden;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu:not([data-submenu-reveal = 'slide']) .brxe-dropdown:not(.open.active) > .brx-dropdown-content > .brxe-dropdown:not([data-submenu-reveal = 'slide'] *){
  visibility: hidden;  
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested.brx-open .brxe-dropdown > .brx-dropdown-content {
  overscroll-behavior: contain;
  min-inline-size: var(--mobile-menu-width);

}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu .brxe-dropdown.open > .brx-submenu-toggle button:not([data-submenu-reveal = 'expand'] button)  {
  min-block-size: calc(var(--top-offset) - 1px);
  inset-block-start: 0;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu .brxe-dropdown.open[data-submenu-reveal = 'slide'] > .brx-submenu-toggle button  {
  min-block-size: calc(var(--top-offset) - 1px);
  inset-block-start: 0;
}

html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header #dwc-nest-menu .brxe-dropdown .brx-submenu-toggle button {
  min-block-size: 0;    
}

/* sidebar css ends*/



/*sidebar in builder*/
/*=== sidebar css ===*/
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header {
  flex-direction: column;
  box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.7);
  --top-offset: 40px;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
  max-block-size: 100dvb;
  padding-block-end: 12rem;
  overscroll-behavior: contain;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #dwc_nav_wrapper {
  position: relative;
  overflow: hidden;
  block-size: 100%;
  transform: translateX(0%);
  visibility: visible;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #dwc-nest-menu .brxe-toggle {
  display: none !important;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu {
  display: flex;
  flex-direction: column;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-header > div {
  display: flex;
  grid-template-columns: 1fr;
  block-size: 100%;
  flex-direction: column;
  justify-content: flex-start;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-menu-wrap {
  inline-size: 100%;
  display: grid;
  grid-template-columns: 1fr;
  block-size: 100%;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-header {
  inline-size: 100%;
  padding-inline: 0;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #mobile_menu_top {
  min-block-size: var(--top-offset);
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #dwc-nest-menu .brx-dropdown-content {
  inset-block-start: calc(var(--top-offset) - 1px) !important;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested.brx-open .brxe-dropdown > .brx-dropdown-content {
  overscroll-behavior: contain;  
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #dwc-nest-menu .brxe-dropdown.open > .brx-submenu-toggle button {
  min-block-size: calc(var(--top-offset) - 1px);
  inset-block-start: 0;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #dwc-nest-menu .brxe-dropdown .brx-submenu-toggle button {
  min-block-size: 0;    
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu {
  margin: 0 !important;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] .brx-nav-nested-items {  
  flex-direction: column !important;  
}
   
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-toggle--open.brxe-toggle {
  display: flex !important;
}
 
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu .brx-nav-nested-items {
  position: relative !Important;
  background: var(--mobile-menu-bg) !important;
  align-items: stretch;
  flex: 1;
}
 
/* MENU CTA (LAST BUTTON) */
:is(.brx-header-left, .brx-header-right)[data-builder-window] [data-last-item-is-button="true"].dwc-nest-menu .brx-nav-nested-items > .menu-item:last-of-type {
  padding-inline: var(--menu-item-inline-padding) !important;
  padding-block: var(--menu-item-block-padding) !important;
}
 
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-menu-top {
  min-block-size: 80px !important;
}
 
:is(.brx-header-left, .brx-header-right)[data-builder-window] .dwc-nest-nav-items {
  overflow-y: scroll;
}

:is(.brx-header-left, .brx-header-right)[data-builder-mode] .brx-dropdown-content {
  min-inline-size: var(--mobile-menu-width);
  position: static;
}

:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
  flex-wrap: nowrap;
}
:is(.brx-header-left, .brx-header-right)[data-builder-window] #brx-header #dwc-nest-menu .brx-dropdown-content {   
  visibility: visible !important;
  opacity: 1;
}

/*OVERLAY SIDEBAR*/


html:not(.dwc-mobile):has([data-overlay-sidebar=true])  {
 --mobile-menu-bg: rgb(255 255 255 / 0%);
  --menu-item-border: solid 1px rgb(255 255 255 / 50%);
 
}

html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) :is(main, footer){
  margin: 0 !important
}

html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) :is(main, footer) :where(section):not(section>section) {
  padding-inline-start: calc(var(--mobile-menu-width) + clamp(1.5rem, calc(0.625vw + 1.375rem), 1.875rem));
  max-inline-size: 100%
}

html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) #brx-header {
  border-radius: var(--overlay-sidebar-radius);
  overflow: hidden;
  background: var(--overlay-sidebar-bg);
  box-shadow: var(--overlay-sidebar-shadow) !important;
  inset: var(--overlay-sidebar-inset);
}

html:not(.dwc-mobile):has([data-overlay-sidebar=true]) :is(.brx-header-left, .brx-header-right):not([data-builder-modee]) .dwc-nest-header{
  backdrop-filter: blur(13px);
  background: transparent !important;
}

html:not(.dwc-mobile):has([data-overlay-sidebar=true]):not([data-builder-modee])  .brx-dropdown-content {
   background-color: rgb(255 255 255 / 100%);
}

/*NO BRX-OPEN STYLES*/
html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) #brx-header .dwc-nest-menu.brxe-nav-nested .brx-nav-nested-items {
  display: flex;
  flex-wrap: nowrap;
  flex-direction: column !important;
}


  html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) .dwc-nest-menu.brxe-nav-nested .brxe-dropdown .brx-dropdown-content {
      visibility: visible;
      min-inline-size: var(--mobile-menu-width) !important;
  }


  html:not(.dwc-mobile) :is(.brx-header-left, .brx-header-right):not([data-builder-window]) .dwc-nest-menu[data-submenu-reveal="expand"] .brxe-dropdown.open>.brx-dropdown-content {
   position: static;
}
class SidebarNavigation {
  constructor(options = {}) {
    // Basic configuration properties
    this.config = {
      minWidth: options.minWidth || MegaMenuCONFIG.minWidth, // Using external minWidth variable
      menuSelector: options.menuSelector || '.dwc-nest-menu',
      openClass: options.openClass || 'brx-open',
      activeClasses: options.activeClasses || ['open', 'active'],
      leftHeaderClass: options.leftHeaderClass || 'brx-header-left',
      rightHeaderClass: options.rightHeaderClass || 'brx-header-right',
      debounceDelay: options.debounceDelay || 100,
      menuItemClickDelay: options.menuItemClickDelay || 300
    };
    
    // Set dependent selectors
    const menuSelector = this.config.menuSelector;
    this.config.submenuToggleSelector = options.submenuToggleSelector || `${menuSelector} .brx-submenu-toggle`;
    this.config.dropdownSelector = options.dropdownSelector || `${menuSelector} .brxe-dropdown`;
    this.config.dropdownContentSelector = options.dropdownContentSelector || `${menuSelector} .brx-dropdown-content`;
    
    // State
    this.previousHeaderClass = null;
    this.dropdownClickHandlers = new Map();
    this.menuHoverHandlers = null;
    this.menuItemClickTimeout = null;
    this.keyboardNavHandler = null;
    this.cachedFocusableElements = null;
    this.cachedElements = {
      menuElement: null,
      navElement: null,
      dropdowns: null,
      dropdownToggles: null,
      menuItems: null
    };
    
    // Bind methods to this instance
    this.handleResize = this.debounce(this.handleMenu.bind(this), this.config.debounceDelay);
    this.handleOutsideClick = this.handleOutsideClick.bind(this);
  }
  
  // Initialize everything - called once
  init() {
    // Wait for DOM to be fully loaded before attaching events
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => {
        this.initAfterDOMLoaded();
      }, { once: true });
    } else {
      this.initAfterDOMLoaded();
    }
    
    return this;
  }
  
  // Separate initialization method to run after DOM is loaded
  initAfterDOMLoaded() {
    // Cache DOM elements once
    this.cacheElements();
    
    // Setup resize event with passive flag
    window.addEventListener('resize', this.handleResize, { passive: true });
    
    // Setup mutation observer for critical class changes only
    this.setupMutationObserver();
    
    // Initial setup based on current screen size
    this.handleMenu();
    
    // Cache focusable elements once if header class is present
    if (this.hasHeaderClass()) {
      this.cacheFocusableElements();
      this.setupMenuFocusNavigation();
    }
  }
  
  // Cache all required DOM elements upfront
  cacheElements() {
    this.cachedElements.menuElement = document.querySelector(this.config.menuSelector);
    
    if (this.cachedElements.menuElement) {
      this.cachedElements.navElement = this.cachedElements.menuElement.querySelector('.dwc-nest-nav-items');
      this.cachedElements.dropdowns = Array.from(document.querySelectorAll(this.config.dropdownSelector));
      this.cachedElements.dropdownToggles = Array.from(document.querySelectorAll(this.config.submenuToggleSelector));
      this.cachedElements.menuItems = Array.from(document.querySelectorAll(`${this.config.menuSelector} .menu-item`));
    }
  }
  
  // Set up a focused mutation observer only for dropdown state changes
  setupMutationObserver() {
    if (!this.cachedElements.dropdowns || this.cachedElements.dropdowns.length === 0) return;
    
    const callback = (mutations) => {
      for (let mutation of mutations) {
        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
          const target = mutation.target;
          const prevClassList = mutation.oldValue ? mutation.oldValue.split(' ') : [];
          const hadBothBefore = prevClassList.includes('open') && prevClassList.includes('active');
          const hasBothNow = target.classList.contains('open') && target.classList.contains('active');
    
          if (hadBothBefore !== hasBothNow) {
            this.updateDropdownAccessibility();
            break; // Only need to update once per batch
          }
        }
      }
    };
    
    // Create observer with optimized options
    this.classObserver = new MutationObserver(callback);
    
    // Observe only the dropdown elements
    this.cachedElements.dropdowns.forEach(dropdown => {
      this.classObserver.observe(dropdown, { 
        attributes: true, 
        attributeFilter: ['class'], 
        attributeOldValue: true 
      });
    });
  }
  
  // Cache focusable elements for keyboard navigation
  cacheFocusableElements() {
    if (!this.cachedElements.navElement) return;
    
    // Get direct children of nav
    const directChildren = Array.from(this.cachedElements.navElement.children);
    
    // Find the first focusable element within each direct child
    this.cachedFocusableElements = directChildren.map(child => {
      // Check if the child itself is focusable
      if (child.matches('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])')) {
        return child;
      }
      // Otherwise, find the first focusable element within this child
      return child.querySelector('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
    }).filter(Boolean); // Remove null/undefined values
  }
  
  // Clean up all event listeners and observers
  destroy() {
    // Clean up the mutation observer
    if (this.classObserver) {
      this.classObserver.disconnect();
      this.classObserver = null;
    }
    
    // Clean up resize listener
    window.removeEventListener('resize', this.handleResize);
    
    // Clean up click handlers
    if (this.dropdownClickHandlers.size > 0) {
      this.dropdownClickHandlers.forEach((handler, toggle) => {
        toggle.removeEventListener('click', handler);
      });
      this.dropdownClickHandlers.clear();
    }
    
    // Clean up hover handlers
    this.cleanupMenuHover();
    
    // Clean up menu item click handlers
    this.cleanupMenuItemClicks();
    
    // Clean up outside click handler
    document.removeEventListener('click', this.handleOutsideClick);
    
    // Clean up keyboard navigation
    if (this.keyboardNavHandler) {
      document.removeEventListener('keydown', this.keyboardNavHandler);
      this.keyboardNavHandler = null;
    }
    
    // Clear any pending timeouts
    if (this.menuItemClickTimeout) {
      clearTimeout(this.menuItemClickTimeout);
      this.menuItemClickTimeout = null;
    }
  }
  
  // Utility methods
  hasHeaderClass() {
    return document.body.classList.contains(this.config.leftHeaderClass) || 
           document.body.classList.contains(this.config.rightHeaderClass);
  }
  
  debounce(func, delay) {
    let timer;
    return (...args) => {
      clearTimeout(timer);
      timer = setTimeout(() => func(...args), delay);
    };
  }

  // Check if an element has all the required active classes
  hasAllActiveClasses(element) {
    return this.config.activeClasses.every(className => element.classList.contains(className));
  }
  
  // Toggle all active classes on an element
  toggleActiveClasses(element) {
    this.config.activeClasses.forEach(className => {
      element.classList.toggle(className);
    });
  }
  
  // Core functionality methods
  handleMenu() {
    if (!this.cachedElements.menuElement) return;
    if (!this.hasHeaderClass() && !this.previousHeaderClass) return;

    const screenWidth = window.innerWidth;
    const isLargeScreen = screenWidth >= this.config.minWidth;
    const menuElement = this.cachedElements.menuElement;

    if (!isLargeScreen) {
      // Save which class was present before removal
      if (this.hasHeaderClass()) {
        this.previousHeaderClass = document.body.classList.contains(this.config.leftHeaderClass) 
          ? this.config.leftHeaderClass 
          : this.config.rightHeaderClass;
        
        // Remove header classes
        document.body.classList.remove(this.config.leftHeaderClass, this.config.rightHeaderClass);
        menuElement.classList.remove(this.config.openClass);
        
        // Reset accessibility attributes
        this.resetAccessibilityAttributes();
      }
      
      // Clean up event handlers for mobile view
      this.cleanupMenuHover();
      this.cleanupMenuItemClicks();
      this.cleanupDropdownHandlers();
      document.removeEventListener('click', this.handleOutsideClick);
      
      return;
    }

    // Large screen behavior
    if (!this.hasHeaderClass() && this.previousHeaderClass) {
      document.body.classList.add(this.previousHeaderClass);
    }

    if (this.hasHeaderClass()) {
      if (!menuElement.classList.contains(this.config.openClass)) {
        menuElement.classList.add(this.config.openClass);
      }
      
      // Setup elements for large screen view
      this.setupMenuHover();
      this.setupMenuItemClicks();
      this.setupDropdownHandlers();
      this.setupMenuFocusNavigation();
      this.updateDropdownAccessibility();
      
      // Ensure outside click handler is set up
      document.removeEventListener('click', this.handleOutsideClick);
      document.addEventListener('click', this.handleOutsideClick, { passive: false });
    }
  }
  
  // Reset accessibility attributes when switching to mobile
  resetAccessibilityAttributes() {
    if (!this.cachedElements.dropdowns) return;
    
    // Remove all inert attributes from dropdown contents
    this.cachedElements.dropdowns.forEach(dropdown => {
      const content = dropdown.querySelector(this.config.dropdownContentSelector);
      if (content) {
        content.removeAttribute('inert');
      }
      
      const button = dropdown.querySelector('button');
      if (button) {
        button.setAttribute('aria-expanded', 'false');
      }
    });
  }
  
  setupMenuFocusNavigation() {
    // Only run if hasHeaderClass() is true and we have focusable elements
    if (!this.hasHeaderClass() || !this.cachedFocusableElements || this.cachedFocusableElements.length === 0) {
      return;
    }
    
    // Clean up previous handler if it exists
    if (this.keyboardNavHandler) {
      document.removeEventListener('keydown', this.keyboardNavHandler, true);
      this.keyboardNavHandler = null;
    }
    
    const navMenu = this.cachedElements.menuElement;
    const focusableElements = this.cachedFocusableElements;
    const firstFocusableElement = focusableElements[0];
    const lastFocusableElement = focusableElements[focusableElements.length - 1];
    
    // Find adjacent focusable elements outside the menu (only once during setup)
    const headerElement = navMenu.closest('header') || document.querySelector('header');
    
    // Prepare variables to hold adjacent elements
    let prevFocusableElement = null;
    let nextFocusableElement = null;
    let firstElementAfterHeader = null;
    
    if (headerElement) {
      // Get all focusable elements within the header - do this once and cache the result
      const headerFocusables = Array.from(
        headerElement.querySelectorAll('a:not([tabindex="-1"]), button:not([tabindex="-1"]), input:not([tabindex="-1"]), select:not([tabindex="-1"]), textarea:not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])')
      ).filter(el => window.getComputedStyle(el).display !== 'none');
      
      // Find the index of our first and last menu elements in one pass
      const menuStartIndex = headerFocusables.indexOf(firstFocusableElement);
      const menuEndIndex = headerFocusables.indexOf(lastFocusableElement);
      
      // Cache the adjacent elements
      if (menuStartIndex > 0) {
        prevFocusableElement = headerFocusables[menuStartIndex - 1];
      }
      
      if (menuEndIndex !== -1 && menuEndIndex < headerFocusables.length - 1) {
        nextFocusableElement = headerFocusables[menuEndIndex + 1];
      }
      
      // Pre-calculate the first element after header - but only if needed
      if (!nextFocusableElement) {
        // Use a more efficient selector that targets immediate children of body that aren't the header
        const selector = 'body > *:not(header)';
        const nonHeaderElements = document.querySelectorAll(selector);
        
        // Only process if we have elements
        if (nonHeaderElements.length > 0) {
          // Create a function to find the first focusable element (used later if needed)
          this.findFirstFocusableAfterHeader = () => {
            for (const element of nonHeaderElements) {
              const focusable = element.querySelector('a:not([tabindex="-1"]), button:not([tabindex="-1"]), input:not([tabindex="-1"]), select:not([tabindex="-1"]), textarea:not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])');
              if (focusable && window.getComputedStyle(focusable).display !== 'none') {
                return focusable;
              }
            }
            return null;
          };
        }
      }
    }
    
    // Create keyboard navigation handler with closure over the cached elements
    this.keyboardNavHandler = (e) => {
      // Quick check for Tab key first
      if (e.key !== 'Tab') return;
      
      // Then check if focus is inside the menu
      if (!navMenu.contains(document.activeElement)) return;
      
      let targetElement = null;
      
      // Handle tab navigation at boundaries only
      if (!e.shiftKey && document.activeElement === lastFocusableElement) {
        // Forward tab from last element
        e.preventDefault();
        e.stopPropagation();
        
        if (nextFocusableElement) {
          targetElement = nextFocusableElement;
        } else if (this.findFirstFocusableAfterHeader) {
          // Only search for elements after header if needed and not already found
          firstElementAfterHeader = this.findFirstFocusableAfterHeader();
          targetElement = firstElementAfterHeader;
        }
        
        // Focus on the target or body as fallback
        setTimeout(() => {
          if (targetElement) {
            targetElement.focus();
          } else {
            document.body.setAttribute('tabindex', '-1');
            document.body.focus();
            document.body.removeAttribute('tabindex');
          }
        }, 10);
      } 
      else if (e.shiftKey && document.activeElement === firstFocusableElement) {
        // Backward tab from first element
        e.preventDefault();
        e.stopPropagation();
        
        setTimeout(() => {
          if (prevFocusableElement) {
            prevFocusableElement.focus();
          } else {
            document.body.setAttribute('tabindex', '-1');
            document.body.focus();
            document.body.removeAttribute('tabindex');
          }
        }, 10);
      }
    };
    
    // Use capture phase for the event
    document.addEventListener('keydown', this.keyboardNavHandler, true);
  }
  
  setupMenuHover() {
    const menuElement = this.cachedElements.menuElement;
    if (!menuElement) return;
    
    // Clean up existing hover handlers first
    this.cleanupMenuHover();
    
    // Create event handlers
    const mouseenterHandler = () => {
      menuElement.classList.add(this.config.openClass);
    };
    
    const mouseleaveHandler = () => {
      menuElement.classList.remove(this.config.openClass);
    };
    
    // Add event listeners with passive flag for better performance
    menuElement.addEventListener('mouseenter', mouseenterHandler, { passive: true });
    menuElement.addEventListener('mouseleave', mouseleaveHandler, { passive: true });
    
    // Store the handlers for cleanup
    this.menuHoverHandlers = {
      element: menuElement,
      mouseenter: mouseenterHandler,
      mouseleave: mouseleaveHandler
    };
  }
  
  cleanupMenuHover() {
    if (this.menuHoverHandlers) {
      const { element, mouseenter, mouseleave } = this.menuHoverHandlers;
      element.removeEventListener('mouseenter', mouseenter);
      element.removeEventListener('mouseleave', mouseleave);
      this.menuHoverHandlers = null;
    }
  }
  
  setupMenuItemClicks() {
    if (!this.cachedElements.menuItems || this.cachedElements.menuItems.length === 0) return;
    
    // Clean up existing handlers first
    this.cleanupMenuItemClicks();
    
    const menuElement = this.cachedElements.menuElement;
    const menuItemHandlers = new Map();
    
    this.cachedElements.menuItems.forEach(item => {
      const clickHandler = () => {
        if (this.hasHeaderClass()) {
          // Clear any existing timeout
          if (this.menuItemClickTimeout) {
            clearTimeout(this.menuItemClickTimeout);
          }
          
          // Set timeout before adding the class
          this.menuItemClickTimeout = setTimeout(() => {
            if (!menuElement.classList.contains(this.config.openClass)) {
              menuElement.classList.add(this.config.openClass);
            }
          }, this.config.menuItemClickDelay);
        }
      };
      
      menuItemHandlers.set(item, clickHandler);
      item.addEventListener('click', clickHandler);
    });
    
    this.menuItemClickHandlers = menuItemHandlers;
  }
  
  cleanupMenuItemClicks() {
    if (this.menuItemClickHandlers && this.menuItemClickHandlers instanceof Map) {
      this.menuItemClickHandlers.forEach((handler, item) => {
        item.removeEventListener('click', handler);
      });
      this.menuItemClickHandlers.clear();
    }
    
    if (this.menuItemClickTimeout) {
      clearTimeout(this.menuItemClickTimeout);
      this.menuItemClickTimeout = null;
    }
  }
  
  setupDropdownHandlers() {
    if (!this.hasHeaderClass() || !this.cachedElements.dropdownToggles) return;
    
    // Clean up existing handlers first
    this.cleanupDropdownHandlers();
    
    this.cachedElements.dropdownToggles.forEach(toggle => {
      const clickHandler = (event) => {
        event.stopPropagation();
        event.preventDefault();
        
        const dropdown = toggle.closest(this.config.dropdownSelector);
        if (dropdown) {
          this.toggleActiveClasses(dropdown);
          this.updateDropdownAccessibility();
        }
      };
      
      this.dropdownClickHandlers.set(toggle, clickHandler);
      toggle.addEventListener('click', clickHandler);
    });
  }
  
  cleanupDropdownHandlers() {
    if (this.dropdownClickHandlers.size > 0) {
      this.dropdownClickHandlers.forEach((handler, toggle) => {
        toggle.removeEventListener('click', handler);
      });
      this.dropdownClickHandlers.clear();
    }
  }
  
  handleOutsideClick(event) {
    if (event.target.tagName === 'A') return;
    if (!event.target.closest(this.config.dropdownSelector)) return;
    if (!event.target.closest(this.config.submenuToggleSelector)) {
      event.preventDefault();
      event.stopPropagation();
    }
  }
  
  updateDropdownAccessibility() {
    // Only run if hasHeaderClass() is true
    if (!this.hasHeaderClass() || !this.cachedElements.dropdowns) return;
    
    this.cachedElements.dropdowns.forEach(dropdown => {
      const content = dropdown.querySelector(this.config.dropdownContentSelector);
      const button = dropdown.querySelector('button');
      
      // Check if dropdown has all active classes
      const isOpen = this.hasAllActiveClasses(dropdown);
      
      if (content) {
        if (isOpen) {
          content.removeAttribute('inert');
        } else {
          content.setAttribute('inert', '');
        }
      }
      
      if (button) {
        button.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
      }
    });
  }
}


const sidebarNav = new SidebarNavigation().init();

Our Local Picks

Curated recommendations from local NYC Westies. Sorted by travel time from event hotel.
Coffee 3 min
Culture Espresso

Specialty coffee shop known for quality coffee and award-winning cookies with a cult-following $

Great flat whites, lattes, and brewed coffee. No pour-overs.

Quick Eats 3 min
Liberty Bagels

Classic New York bagel shop with a wide selection of fresh bagels and spreads $

Can't go wrong with their lox cream cheese on an everything bagel. Their Jalapeño everything epic is epic! Want to eat like a true New Yorker? Don't toast the bagel!

Restaurants 3 min
Zoob Zib Thai

Thai noodle bar known for crispy duck noodle soup and well-balanced, authentic dishes $$

Great place for the usual suspects - pad thai, drunken noodles, etc. Perfect if you're really hungry!

Restaurants 4 min
Patiala Indian Grill & Bar

Cozy, elegantly decorated restaurant serving a variety of traditional Indian fare including curries, plus Americanized versions, all cooked fresh. $$$

Quick Eats 4 min
Los Tacos Hermanos

Walk-up taco window with grilled carne asada, chicken, and cactus tacos $

Budget-friendly - tacos under $5

Quick Eats 5 min

Lifestyle 1104 Juice Bar

Vegan juice bar with fresh-pressed juices, smoothies, and acai bowls $

Highly customizable options

Restaurants 5 min
Gosuke

Japanese restaurant with sushi, sashimi, and tempura from chefs with 50+ years experience $$$

Inside the Henn Na Hotel past the giant animatronic T-Rex

Restaurants 6 min
District Tap House

Late-night outpost for craft beer, cocktails & creative bar eats in a dark-wood setting with TVs. $$

"Shockingly good food" says one NYC westie

Quick Eats 6 min
Brooklyn Fare

Upscale grocery with a prepared foods counter, butcher shop, fresh-baked bread, and curated cheeses $$

Fun fact: there's a 2-star Michelin restaurant hidden through a door in the back

Quick Eats 7 min
NY Pizza Suprema

No-frills NYC slice joint across from Penn Station, serving classic New York pizza since 1964 $

Quick Eats 7 min
Dainobu Gourmet Deli

Japanese gourmet deli with freshly made bento boxes, sushi, onigiri, and Japanese groceries $$

Microwave and seating area upstairs

Restaurants 7 min
Zen Ramen & Sushi

Japanese ramen and sushi $$

Rice noodle (gluten-free) options available

Coffee 8 min
Cafe Grumpy

Hip local coffeehouse chain serving house-roasted specialty brews in a relaxed setting. $$

Another of the NYC coffee greats. Offers a seasonal drink menu.

Quick Eats 8 min
Los Tacos No. 1

Authentic Mexican tacos, burritos, and quesadillas at the Penn Station location $

No seating - standing counters only

Restaurants 8 min

Pho 35

Vietnamese pho and noodle soups $

Any pho here is top quality. Dine-in rather than take out!

Restaurants 8 min
Beyond Sushi

100% vegan restaurant with plant-based sushi rolls, dumplings, udon, and a full cocktail bar $$

Restaurants 9 min
Papa San

Delicious Peruvian-Japanese fusion dishes, including eel pizza, scallop ceviche, and wagyu tri-tip. Fun and lively atmosphere and attentive, friendly service. $$$

Restaurants 9 min
Lovely's Old Fashioned

Hamburger restaurant serving amazing burgers, onion rings, and pistachio cake. Old-school 50s diner vibe with a modern twist, and the flavorful Charlotte’s Special. $$

Attractions 9 min
Macy’s Herald Square

The world’s largest department store

Ride the last functioning wooden escalators in the world!

Attractions 10 min
The High Line

Elevated park on a former railway line, stretching from Hudson Yards to the Meatpacking District

Open in winter 7am-8pm. Dress warm.

Quick Eats 10 min
Kati Shop

Thai fast-casual focused on curries. 100% gluten-free and nut-free. $

Drinks 10 min
The Ragtrader & Bo Peep

Two-in-one venue in a converted garment factory: lively gastropub upstairs, hidden speakeasy with live piano downstairs $$

Excellent espresso martinis and other craft cocktails

Restaurants 10 min
Keens Steakhouse

Legendary NYC steakhouse open since 1885, famous for its mutton chop and one of the city’s great old-world dining rooms $$$

Reservations strongly recommended

Tea & Dessert 11 min
HEYTEA

Chinese bubble tea brand known for cheese-foam-topped teas and fruit tea combinations $

Coffee 11 min
Ten Thousand Coffee

Korean-style specialty coffee with creative drinks like purple sweet potato latte, plus fresh-baked croissants $

Offers pour-overs and unique coffee drink options!

Restaurants 11 min
Cho Dang Gol

Korean restaurant specializing in housemade tofu and traditional homestyle dishes $$

They make their own tofu in-house

Coffee 12 min
St Kilda Coffee

Melbourne-inspired subterranean cafe with strong flat whites, cortados, and vegan baked goods $

Top notch! Offers pour-overs

Quick Eats 12 min
NAYA

Lebanese fast-casual with build-your-own bowls, rolls, and salads featuring chicken shawarma and falafel $

Attractions 12 min
Birdland Jazz Club

Legendary midtown jazz club with nightly live shows from world-class musicians $$

Check the schedule and reserve online - shows sell out

Restaurants 12 min
HanGawi

Upscale vegan Korean restaurant with traditional shoes-off floor seating and a serene atmosphere $$$

Michelin Bib Gourmand. Dinner only weekdays; open from 1pm weekends.

Attractions 13 min
The Vessel

Honeycomb-shaped climbable sculpture at Hudson Yards with views of the city and the Hudson River $

Reopens Feb 27 after multiple closures over three years.

Coffee 13 min
Frisson Espresso

Hell’s Kitchen cafe with espresso drinks, smoothies, acai bowls, and house-baked pastries $

Coffee 13 min
Bird & Branch

Hell’s Kitchen coffee roaster with Asian-inspired pastries (black sesame, matcha) and Ippodo matcha drinks $

Standout black sesame and matcha pastries alongside Ippodo-grade matcha drinks

Quick Eats 13 min
All’Antico Vinaio

Florentine sandwich shop famous for overstuffed schiacciata with cured meats and fresh ingredients $

Originally from Florence - the NYC outpost lives up to the hype

Attractions 14 min
Times Square

The iconic crossroads of the world

Everyone should visit once (and maybe only once).

Quick Eats 14 min
The Kati Roll Company

Indian street food spot specializing in Kolkata-style kati rolls – spiced fillings wrapped in warm paratha $

Restaurants 14 min
Mercado Little Spain

Spanish food hall by Jose Andres at Hudson Yards with tapas, paella, and jamon from multiple counters and sit-down spots $$

Great for groups - everyone can order from different counters

Attractions 14 min
Edge NYC

The highest outdoor observation deck in the Western Hemisphere – 1,100 feet up with a glass floor and views in every direction $$$

Tickets from $47. Best on a clear day.

Attractions 14 min
Empire State Building

Iconic Art Deco skyscraper with observation decks on the 86th and 102nd floors $$$

Attractions 15 min
The Museum at the Fashion Institute of Technology (FIT)

Best known for its innovation and award-winning exhibitions, find a permanent collection of more than 50,000 garments and accessories dating from the 18th century to the present.

Attractions 15 min
Kinokuniya New York

Japanese bookstore and stationery shop across from Bryant Park

Restaurants 15 min
Nan Xiang Xiao Long Bao

Shanghai-style soup dumpling specialist in Koreatown $

Restaurants 15 min
The Kunjip

One of Koreatown’s oldest restaurants with generous portions and a huge menu of Korean staples $$

Open nearly 24 hours. Great for after late night dancing!

Attractions 15 min
Gagopa Karaoke

Korean karaoke with private rooms and a massive song library in multiple languages $$

BYOB allowed

Restaurants 15 min
Turntable Chicken Jazz

Korean fried chicken and beer towers in a buzzy Koreatown space with a DJ spinning vinyl $$

Open until 2am Fri-Sat

Attractions 16 min
Bryant Park

Midtown green space behind the public library with ice skating, food vendors, and seating

Last weekend of ice rink season - closes March 1. Free admission but requires booking a time slot. Skate rentals available.

Quick Eats 16 min
Woorijip

Korean cafeteria-style grab-and-go with banchan, kimbap, and hot dishes in Koreatown $

One of the best cheap eats in Midtown

Restaurants 16 min
BCD Tofu House

Korean restaurant known for bubbling-hot soft tofu stew (soondubu jjigae) $$

Open until 5am Fri-Sat - great after late-night dancing

Restaurants 16 min
Jongro BBQ

Korean BBQ in Koreatown with tabletop grills and a solid meat selection $$

Open until 1am Fri-Sat

Restaurants 16 min
P.S. Kitchen

100% plant-based restaurant with globally inspired comfort food and craft cocktails $$

All profits support charitable causes

Tea & Dessert 16 min
Lady M

Japanese-French patisserie famous for its delicate mille crepe cakes with paper-thin layers $$

The signature mille crepe is a must

Attractions 17 min
The Compleat Strategist

Board games, RPGs, card games, and strategy game shop open since 1977

Tea & Dessert 17 min
Prince Tea House

Chinese tea house with elaborate tea service presentations and traditional tea ceremonies $

Attractions 17 min
The Morgan Library & Museum

Rare books, manuscripts, and art in J.P. Morgan’s original private library $$

Restaurants 19 min
Her Name is Han

Modern Korean restaurant with a refined take on traditional homestyle dishes $$

Reservations recommended

Attractions 20 min
New York Public Library

Beaux-Arts landmark with free exhibits, ornate reading rooms, and the iconic lion statues

Restaurants 20 min
Briciola

Rustic Italian wine bar in Hell’s Kitchen with cicchetti (small plates), fresh pasta, and a curated Italian wine list $$

From a James Beard award-winning chef

Restaurants 20 min

Olle

Homestyle Korean known for galbi jjim (braised short ribs, carved tableside) and naengmyeon (cold noodles) $$

Reservations recommended - always packed

Quick Eats 20 min
Le Botaniste

100% organic, vegan, and gluten-free bowls, soups, and natural wines $$

Next to Bryant Park - get food to-go and eat in the park

Restaurants 20 min
Ippudo Westside

Acclaimed Hakata-style tonkotsu ramen from Japan with rich pork broth and springy noodles $$

Quick Eats 21 min
Xi’an Famous Foods

Hand-pulled noodles and spicy cumin lamb burgers from the beloved NYC chain $

The 34th St location is closed - this Midtown spot is the nearest

Restaurants 21 min
Raku

Hand-made udon noodles in rich broths alongside Japanese small plates $$

Drinks 22 min
Valerie

Art Deco cocktail bar with 90+ gins, creative American fare, and live jazz on Sundays $$

Live jazz on Sunday

Coffee 23 min
Felix Roasting Co.

Ornate specialty coffee shop with mosaic floors, craft espresso, and Supermoon Bakehouse pastries in a stunning NoMad space $

Worth the walk for the interior alone

Restaurants 23 min
MáLà Project Bryant Park

Customizable Sichuan dry pot (mala xiang guo) where you pick your ingredients and spice level $$

Michelin Bib Gourmand recommended

Attractions 23 min
Rockefeller Center

Art Deco complex with Top of the Rock observation deck, NBC Studios, and the famous plaza $$

Attractions 26 min
Grand Central Terminal

Beaux-Arts train station with a celestial ceiling, dining concourse, and whispering gallery

Look for the one soot-covered patch on the ceiling and research its meaning. Also try the Whispering Gallery with a friend!

Attractions 27 min
Kalustyan’s

Legendary specialty food and spice shop with ingredients from around the world, open since 1944

Restaurants 12 min
Coppelia

Pan-Latin diner with Cuban, Peruvian, and Colombian dishes. DJ sets on weekend nights. $$

Open 24 hours - perfect after late-night social dancing

Attractions 12 min
Chelsea Market

Indoor food hall and shopping market in a former Nabisco factory $$

Walkable via the High Line from Hudson Yards

Tea & Dessert 13 min
Té Company

Taiwanese tea bar in the West Village with a curated selection of high-mountain oolongs and seasonal pairings $

Intimate space - pair a tea flight with their pineapple linzer cookie

Attractions 13 min
Comedy Cellar

Famous Greenwich Village comedy club where top comedians drop in for surprise sets $$

Book online in advance - walk-ins are tough on weekends

Restaurants 15 min
Senza Gluten

100% gluten-free Italian restaurant – the entire kitchen is celiac-safe with real pasta and bread $$

Cash and AmEx only - no Visa/Mastercard

Attractions 15 min
MoMA

One of the world’s most influential modern art museums $$

Attractions 15 min
American Museum of Natural History

Dinosaur fossils, planetarium, and natural science exhibits across 45 halls $$

Quick Eats 16 min
Urban Hawker

Singaporean hawker-style food hall with 17 vendor stalls – the first authentic Singapore street food center in the U.S. $$

Hainanese chicken rice, laksa, prawn noodles, and more under one roof

Attractions 16 min
Whitney Museum of American Art

American art museum at the southern end of the High Line $$

Free Fridays 5-10pm. Timed tickets required, capacity limited.

Tea & Dessert 20 min
Levain Bakery

Bakery famous for massive, gooey cookies – the chocolate chip walnut is legendary $

Tea & Dessert 20 min
Dominique Ansel Bakery

French pastry shop from the inventor of the Cronut – the croissant-doughnut hybrid that took NYC by storm $$

Fresh Cronuts daily at 8am - they sell out fast

Attractions 21 min

Fifth Avenue

Manhattan’s premier luxury shopping corridor from Saks to Bergdorf Goodman

Coffee 21 min
Devoción

Colombian coffee roaster with a stunning greenhouse-like interior filled with living plants $

Beans arrive from Colombia within weeks of harvest. Offers pour-overs. If walking, stroll through Madison Square Park

Drinks 21 min

Lai Rai

Vietnamese natural wine bar with curated French, Italian, and Asian wines, plus rotating ice cream flavors like fish sauce caramel $$

Drinks 22 min
The Back Room

The Back Room is one of only two speakeasies in New York City that operated during Prohibition and is still in existence today. $$

Jazz & dancing on Monday nights. Enter through the underground alleyway.

Tea & Dessert 25 min
Spot Dessert Bar

Creative Asian-fusion dessert restaurant with plated desserts like the Golden Toast and Matcha Lava Cake $$

Open until 1am Fri-Sat

Drinks 25 min
Double Chicken Please

Culinary cocktail bar ranked among the World’s Best Bars with creative cocktails on tap $$

Reservations recommended

Drinks 25 min
Sake Bar Decibel

NYC’s original sake bar since 1993 – a graffiti-walled basement with 100+ sakes and Tokyo Golden Gai vibes $$

Look for the blinking 'On Air' sign

Restaurants 27 min
Katz’s Delicatessen

Legendary Jewish deli on the Lower East Side serving pastrami and corned beef sandwiches since 1888 $$

Take the F from 34th St-Herald Sq to 2nd Ave

Drinks 27 min
Parcelle Chinatown

Walk-in-friendly wine bar with 500+ bottles, a full dinner menu, and a downstairs cocktail bar on weekends $$

Attractions 28 min
The Frick Collection

European masterpieces displayed in a Gilded Age mansion on the Upper East Side $$

Recently renovated. Vermeer, Rembrandt, and Bellini in a stunning Gilded Age setting.

Drinks 30 min
Bar Francis

Speakeasy cocktail bar hidden behind Hungry Ghost Coffee in Clinton Hill, with inventive drinks and oysters $$

Enter through the coffee shop

Drinks 35 min
Eavesdrop

Greenpoint listening bar with a custom-built sound wall, vinyl DJ sets, and Japanese-inspired interior $$

Craft cocktails and natural wines - the emphasis is on listening

Attractions 35 min
The Metropolitan Museum of Art

World-renowned art museum with collections spanning 5,000 years $$