/*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 .dwc-nest-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;
}

body: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 .dwc-nest-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;
}

:where(.brx-header-left, .brx-header-right)[data-builder-mode]:not(:has(.dwc-sidebar)) .dwc-nest-menu-top::before {
    content: 'this space is the back text bar';
    padding: 1rem;
    background-color: gray;
    color: white;
    width: 100%;
    text-transform: uppercase;
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 1px;
}
 
/* 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();

Algemene voorwaarden

Onderstaande algemene voorwaarden van Equanimity Training & Coaching zijn gedeponeerd bij de Kamer van Koophandel onder KvK-nummer 34366414.

1. Definities

1.1. Overeenkomst: de overeenkomst tussen Opdrachtnemer en Opdrachtgever tot afname van één of meer Opleidingsproducten van Opdrachtnemer.

1.2. Opdrachtnemer: Equanimity, gevestigd te 1087 VR Amsterdam, aan de Tip Maruggstraat 10 en ingeschreven in het handelsregister van de Kamer van Koophandel onder nummer 34366414.

1.3. Opleidingsproduct(en): de opleiding, cursus of training die door Opdrachtnemer wordt aangeboden.

1.4. Open Inschrijving(en): elke inschrijving voor een Opleidingsproduct van Opdrachtnemer die niet op maat is gemaakt en die open staat voor inschrijving voor eenieder.

1.5. Individuele Begeleiding en Coaching: een Opleidingsproduct van Opdrachtnemer dat niet aan een groep, maar aan een individu wordt gegeven.

1.6. In Company- en Maatwerktrajecten: alle Opleidingsproducten die op maat worden aangeboden aan een Opdrachtgever.

1.7. Opdrachtgever: de opdrachtgever van Opdrachtnemer. Opdrachtgevers kunnen zijn:
a. Natuurlijke personen die (in het kader van de uitoefening van een beroep of bedrijf) aan een opleidingsproduct van Opdrachtnemer deelnemen via een Open Inschrijving.
b. Ondernemingen die Opdrachtnemer opdracht geven voor het verzorgen van In Company- en Maatwerktrajecten voor personeelsleden.

1.8. Voorwaarden: deze algemene voorwaarden

2. Toepasselijkheid en wijziging Voorwaarden

2.1. De Voorwaarden zijn, tenzij schriftelijk anders overeengekomen, van toepassing op alle overeenkomsten met Opdrachtgever en op aanvullende opdrachten en vervolgopdrachten.

2.2. De toepasselijkheid van eventuele inkoopvoorwaarden of andere voorwaarden van Opdrachtgever wordt uitdrukkelijk van de hand gewezen.

2.3. Opdrachtnemer is gerechtigd de Voorwaarden te wijzigen. Wijzigingen van de Voorwaarden gelden ook ten aanzien van bestaande overeenkomsten. Opdrachtnemer zal wijzigingen van de Voorwaarden bekend maken op htp://www.equanimity.nu. De gewijzigde Voorwaarden treden 2 weken na bekendmaking in werking, of zoveel later als in de bekendmaking is bepaald.

3. Tarieven algemeen

3.1. Betaling van facturen van Opdrachtnemer dient te geschieden binnen veertien dagen na factuurdatum, tenzij anders vermeld op de factuur.

3.2. Opdrachtnemer is gerechtigd haar verplichtingen jegens Opdrachtgever, waaronder maar niet beperkt tot de deelname van Opdrachtgever aan een Opleidingsproduct van Opdrachtnemer, op te schorten zolang Opdrachtgever niet aan alle (betalings)verplichtingen heeft voldaan.

4. Tarieven Open Inschrijvingen

4.1. Opdrachtnemer factureert Opdrachtgevers van Open Inschrijvingen direct na inschrijving ongeacht de aanvangsdatum van het Opleidingsproduct.

4.2. De betaling moet te allen tijde hebben plaatsgevonden voor aanvangsdatum van het Opleidingsproduct.

4.3. Eventuele andere opdracht gebonden kosten en administratie- en bureaukosten kunnen door Opdrachtnemer aan Opdrachtgever worden doorbelast.

5. Tarieven In Company- en Maatwerktrajecten, Individuele Begeleiding en Coaching

5.1. Partijen kunnen bij het tot stand komen van de Overeenkomst een vast honorarium overeenkomen.

5.2. Indien geen vast honorarium wordt overeengekomen, zal het honorarium worden vastgesteld op grond van de werkelijk bestede uren. Het honorarium wordt berekend volgens de gebruikelijke uurtarieven van Opdrachtnemer, geldende voor de periode waarin werkzaamheden worden verricht, tenzij een daarvan afwijkend uurtarief is overeengekomen.

5.3. Opdrachtnemer zal maandelijks of per deelopdracht overgaan tot tussentijdse declaratie van de werkzaamheden tenzij sprake is van een kleine opdracht in welk geval Opdrachtnemer aan het einde van de opdracht tot declaratie zal overgaan.

5.4. Het is Opdrachtnemer toegestaan de tarieven halfjaarlijks te wijzigen in het kader van een complete tariefswijziging, met dien verstande dat nieuwe tarieven minstens één maand voor inwerkingtreding aan Opdrachtgever moeten zijn meegedeeld.

5.5. Opdrachtnemer is gerechtigd prijsstijgingen door te berekenen indien tussen het moment van aanbieding en levering, de tarieven ten aanzien van bijv. lonen zijn gestegen.

5.6. Opdrachtnemer mag het honorarium verhogen wanneer tijdens de uitvoering van de werkzaamheden blijkt dat de oorspronkelijk overeengekomen dan wel verwachte hoeveelheid werk in zodanige mate onvoldoende werd ingeschat bij het sluiten van de Overeenkomst dat in redelijkheid niet van de Opdrachtnemer kan worden verwacht de overeengekomen werkzaamheden te verrichten tegen het oorspronkelijke overeengekomen honorarium. Opdrachtnemer zal Opdrachtgever in dat geval van het voornemen tot verhoging van het honorarium of tarief in kennis stellen. Opdrachtnemer zal daarbij de omvang van en datum waarop de verhoging zal ingaan, vermelden.

5.7. Tijd-, reis- en verblijfskosten samenhangend met vervoer en overnachting van medewerkers van Opdrachtnemer in het kader van de opdracht kunnen door Opdrachtnemer aan Opdrachtgever worden gefactureerd.

5.8. Indien door Opdrachtnemer of door Opdrachtnemer ingeschakelde derden in het kader van de opdracht werkzaamheden worden verricht op de locatie van Opdrachtgever of een door Opdrachtgever aangewezen locatie, draagt Opdrachtgever kosteloos zorg voor de door die medewerkers in redelijkheid gewenste faciliteiten.

6. Inschakeling derden en vervanging docenten/trainers

6.1. Indien en voor zover een goede uitvoering van de Overeenkomst dit vereist, heeft Opdrachtnemer het recht bepaalde werkzaamheden te laten verrichten door derden.

6.2. Opdrachtnemer kan in overleg met Opdrachtgever de samenstelling van de opdrachtleiding of het opdrachtteam wijzigen, indien zij meent dat dit noodzakelijk is. De wijziging mag niet ten kosten gaan van de kwaliteit van de het Opleidingsproduct en mag de continuïteit van de werkzaamheden niet ongunstig beïnvloeden.

7. Non-concurrentie

Geen van de partijen mag tijdens de uitvoering van de opdracht en binnen één jaar na het einde van de Overeenkomst een hulppersoon (bv. een freelancer) van de andere partij in dienst nemen of daarmee over indiensttreding onderhandelen.

8. Intellectueel eigendomsrecht

8.1. Alle intellectuele eigendomsrechten, waaronder maar niet beperkt tot het auteursrecht, databankrecht, merkenrecht, handelsnaamrecht of octrooirecht, en overige rechten op en in verband met het cursusmateriaal berusten bij Opdrachtnemer, de docent en/of derden.

8.2. Het is Opdrachtgever niet toegestaan om zonder voorafgaande schriftelijke toestemming van de rechthebbende cursusmateriaal geheel of gedeeltelijk te verveelvoudigen of openbaar te maken.

8.3. Het cursusmateriaal geldt uitsluitend voor eigen gebruik van Opdrachtgever. Opdrachtgever staat er voor in dat haar werknemers zich ook persoonlijk verplichten om deze voorwaarde na te leven.

8.4. Niets in deze Overeenkomst kan worden uitgelegd als een overdracht van intellectuele eigendomsrechten met betrekking tot cursusmateriaal.

9. Geheimhouding/vertrouwelijke informatie

9.1. Beide partijen zijn verplicht tot geheimhouding van alle vertrouwelijke informatie die zij in het kader van de Overeenkomst van elkaar of uit andere bron hebben verkregen.

9.2. Opdrachtnemer zal de vertrouwelijke informatie alleen gebruiken om de Opdrachtgever te (blijven) informeren over Opleidingsproducten of daaraan gerelateerde informatie.

10. Persoonsgegevens

10.1. Opdrachtnemer gebruikt de door haar ontvangen persoonsgegevens van Opdrachtgever om Opdrachtgever te informeren over Opleidingsproducten.

10.2. Opdrachtnemer verwerkt de door de Opdrachtgever verstrekte persoonsgegevens in overeenstemming met het privacybeleid van Opdrachtnemer. Opdrachtnemer garandeert dat de betrokkenen van wie persoonsgegevens worden verstrekt zijn geïnformeerd over de verwerking van hun gegevens door Opdrachtgever.

11. Annulering

11.1. Voor Opdrachtgevers van Open Inschrijvingen geldt een wettelijk bedenktermijn van 14 dagen waarbinnen Opdrachtgever alsnog kan besluiten van de verbintenis af te zien. Dit dient altijd digitaal of schriftelijk te gebeuren. Bij inschrijvingen binnen 14 dagen voor aanvang van de training geldt de bedenktermijn, maar vervalt op het eerste lesmoment en de cursist hierbij aanwezig is geweest.

11.2. Bij annulering of wijziging van de deelnamedatum door de Opdrachtgever van Open Inschrijvingen en van Individuele Begeleiding en Coaching vanaf de datum van inschrijving tot 10 dagen voor de eigenlijke aanvang van de opdracht worden geen deelnamekosten in rekening gebracht. Bij annulering of wijziging van de deelnamedatum binnen 10 dagen voor de eigenlijke aanvang van de opdracht wordt 50% van de deelnamekosten aan Opdrachtgever in rekening gebracht. Bij annulering of wijziging van de deelnamedatum binnen 5 dagen voor de eigenlijke aanvang van de opdracht wordt 100% van de deelnamekosten aan Opdrachtgever in rekening gebracht. Bij annulering restitueren wij binnen 14 dagen.

11.3. Bij annulering of wijziging van In Company- Maatwerktrajecten binnen 2 maanden voor de eigenlijke aanvang van de opdracht worden alle daadwerkelijke door Opdrachtnemer gemaakte en door Opdrachtnemer te specificeren kosten aan Opdrachtgever gefactureerd. Bij annulering of wijziging binnen 4 weken voor de eigenlijke aanvang van de opdracht wordt 50% van het totaalbedrag van de eerste overeengekomen leveringstermijn aan Opdrachtgever gefactureerd. Bij annulering of wijziging binnen 2 weken voor de eigenlijke aanvang van de opdracht wordt 100% van het totaalbedrag van de opdracht aan Opdrachtgever gefactureerd.

11.4. Indien voor deelname door Opdrachtnemer kosten zijn gemaakt voor hotel en/of conferentieoord worden alle kosten die door het hotel en/of conferentieoord aan Opdrachtnemer worden berekend aan Opdrachtgever gefactureerd.

11.5. Eventuele terugbetalingen door Opdrachtnemer aan Opdrachtgever resulterende uit annulering of wijzigingen van de aanvangsdatum worden binnen 14 dagen voldaan door de door Opdrachtnemer.

12. Aansprakelijkheid

12.1. Hoewel met betrekking tot de inhoud van Opleidingsproducten van Opdrachtnemer en cursusmateriaal de uiterste zorg is nagestreefd, kan Opdrachtnemer niet instaan voor de afwezigheid van fouten in of de volledigheid van de Opleidingsproducten van Opdrachtnemer en het cursusmateriaal. Opdrachtnemer en de docenten/trainers zijn, voor zover maximaal is toegestaan op grond van toepasselijk recht, niet voor dergelijke fouten of onvolledigheden aansprakelijk.

12.2. Behoudens opzet of bewuste roekeloosheid aan de zijde van Opdrachtnemer, is Opdrachtnemer niet aansprakelijk voor schade die Opdrachtgever lijdt als gevolg van deelname aan een Opleidingsproduct.

12.3. Indien Opdrachtnemer aansprakelijk mocht zijn voor enigerlei schade, dan is de aansprakelijkheid van Opdrachtnemer beperkt tot maximaal de factuurwaarde van de opdracht waarop de aansprakelijkheid betrekking heeft.

12.4. Opdrachtnemer is nimmer aansprakelijk voor indirecte schade, daaronder begrepen gevolgschade, gederfde winst, gemiste besparingen en schade door bedrijfsstagnatie.

12.5. Opdrachtgever vrijwaart Opdrachtnemer voor eventuele aanspraken van derden, die in verband met de uitvoering van de Overeenkomst schade lijden en welke aan Opdrachtgever toerekenbaar is.

13. Overmacht

13.1. Ziekte en tijdelijke of blijvende arbeidsongeschiktheid van Opdrachtnemer ontslaat Opdrachtnemer van het nakomen van de overeengekomen leveringstermijn of van zijn leveringsplicht, zonder dat Opdrachtgever recht heeft op schadevergoeding.

13.2. Indien de overmachtssituatie langer duurt dan 6 maanden is ieder der partijen gerechtigd de Overeenkomst te ontbinden, zonder verplichting tot vergoeding van schade aan de andere partij.

13.3. Voor zoveel Opdrachtnemer ten tijde van het intreden van overmacht inmiddels gedeeltelijk de verplichtingen uit de Overeenkomst is nagekomen of deze zal kunnen nakomen en aan het nagekomen respectievelijk na te komen gedeelte zelfstandige waarde toekomt, is Opdrachtnemer gerechtigd om het reeds nagekomen respectievelijk na te komen gedeelte separaat te declareren. Opdrachtgever is gehouden deze declaratie te voldoen als ware het een afzonderlijke overeenkomst.

14. Vragen en klachten

14.1. Vragen over de dienstverlening, cursusaanbod of van administratieve aard kunnen per e-mail door Opdrachtgever worden gesteld via het e-mailadres boris@equanimity.nu. Opdrachtnemer zal vragen uiterlijk binnen 7 dagen schriftelijk of per e-mail beantwoorden of een bevestiging sturen met daarin de verachtte termijn waarbinnen vraag zal worden beantwoord.

14.2. Equanimity beschikt over een klachtenregeling waarin alles geregeld is omtrent klachten. Deze vormt een onlosmakelijk deel van deze Algemene Voorwaarden en is voor iedereen in te zien op https://equanimity.nu/klachtenregeling/. Een PDF kan op verzoek worden toegezonden.

14.3. Wie een overeenkomst heeft of wil aangaan met Equanimity is in geval van een klacht verplicht deze klachtenregeling te hanteren. Iedereen die bij een klacht betrokken is zal zijn volle medewerking geven deze langs de daarin aangegeven wegen op te lossen.

14.4. Wie een klacht heeft, probeert deze eerst op te lossen met Equanimity. Als dit niet lukt of er zijn redenen waarom dit niet kan staat het de klager vrij een gerechtelijke procedure te starten of de onafhankelijke klachtenfunctionaris om een voor alle partijen bindende uitspraak te vragen. Alle betrokkenen zullen zolang een klacht niet is opgelost er naar derden geen ruchtbaarheid aan geven en met alle gegevens vertrouwelijk omgaan.

15. Toepasselijk recht

15.1. Op alle rechtsbetrekkingen waarbij Opdrachtnemer partij is, is uitsluitend Nederlands recht van toepassing, ook indien aan een verbintenis geheel of gedeeltelijk in het buitenland uitvoering wordt gegeven of indien de bij de rechtsbetrekking betrokken partij aldaar woonplaats heeft.

15.2. De rechtbank Amsterdam is bij uitsluiting bevoegd van geschillen kennis te nemen, tenzij de wet dwingend anders voorschrijft.

15.3. Partijen zullen pas een beroep op de rechter doen, nadat zij zich tot het uiterste hebben ingespannen een geschil in onderling overleg te beslechten.

geweldloze commuequanimity emotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartspelemotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartenequanimity emotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartspelemotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartenemotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartenequanimity emotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartspelequanimity emotiekaarten gevoelenskaarten behoeftekaarten geweldloze communicatie kaartspel