/*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();

"The objective of Nonviolent Communication is not to change people and their behavior in order to get our way: it is to establish relationships based on honesty and empathy, which will eventually fulfill everyone's needs."
- Marshall Rosenberg

wat is geweldloze communicatie wat is verbindende communicatie wat is nonviolent communication

Geweldloos communiceren is in contact komen met je behoeften en luisteren met empathie

Wat is Verbindende of Geweldloze communicatie?

Wat is Geweldloze communicatie? De termen Geweldloze en Verbindende communicatie worden vaak door elkaar gebruikt. De term ‘Geweldloos‘ refereert aan het concept van Nonviolence of Ahimsa dat staat voor het ethische principe om in geen geval schade toe te brengen aan onszelf, aan anderen of aan de wereld. De term Verbindende communicatie wordt vaak gebruikt om uit te drukken op welke manier we dit doen: door verbinding te maken met onze eigen en andermans gevoelens en behoeften

“Geweldloze communicatie? Heb jij dat nodig dan?” is een reactie die je wel eens krijgt als je aan iemand vertelt dat je een training of cursus Geweldloos communiceren hebt gevolgd. Toch kent iedereen het vervelende gevoel waarmee je blijft zitten als je een aanvaring hebt gehad met een collega of als je het idee hebt dat je partner, een vriend of familielid je niet begrijpt of je kind niet echt naar je luistert. Het aantal burn-outs en echtscheidingen is hoger dan ooit en veel mensen maken zich druk over gescheld op social media, korte lontjes en toenemende polarisatie in de samenleving

Hoe werkt Geweldloze communicatie?

Het model voor ‘Nonviolent communication’ is ontwikkeld door de Amerikaanse psycholoog Dr. Marshall Rosenberg (1934-2015) en helpt je een manier van luisteren en communiceren eigen te maken die gericht is op gevoelens en behoeften in plaats van oordelen en verwijten. Dit is geen passieve, ingewikkelde, softe of vermijdende manier van communiceren. Het gaat juist over actief je grenzen aangeven, helderheid scheppen, mogen zijn wie je bent, stoppen met aardig zijn en je emoties de ruimte geven. Geweldloos communiceren is contact maken met jezelf en anderen en elkaars menselijkheid kunnen zien. Het heeft niet tot doel om iemand te veranderen, te manipuleren of te overtuigen. Het is gericht op het erkennen van verschillen, het zien van overeenkomsten en het komen tot strategieën die voor iedereen werken.

Wat levert een training Geweldloze communicatie op?

In de trainingen Verbindende / Geweldloze communicatie leer je hoe je kunt omgaan met emoties tijdens gesprekken en hoe je echt contact maakt met jouw gesprekspartner. Je leert je eigen gevoelens en behoeften te herkennen, verzoeken helder en objectief te verwoorden maar tegelijk open te blijven staan voor wat de ander te zeggen heeft. De trainingen zijn praktisch van aard en bevatten veel oefeningen en alledaagse voorbeelden zodat je meteen de positieve invloed ervaart die Geweldloze communicatie kan hebben op je persoonlijke en werkende leven. Het (be)oefenen van Geweldloze communicatie levert je het volgende op:

  • Helderheid over je eigen behoeften
  • Creatieve oplossingen voor problemen
  • Grenzen kunnen aangeven
  • Beter kunnen omgaan met kritiek en verwijten
  • Meer ontspanning tijdens gesprekken
  • Je effectief kunnen uitdrukken in lastige situaties
  • Betekenisvol contact met anderen
  • Minder gedoe, en dus meer tijd en energie voor andere dingen

Onze trainingen Geweldloze communicatie

Equanimity werkt samen met verschillende gecertificeerde trainers en heeft een aanbod voor zowel particulieren (open inschrijving) als op maat gemaakte trainingen voor organisaties en bedrijven, en speciale beroepsgroepen zoals (para)medici, jeugd- en gezinsprofessionals en werknemers in de creative industrie.

Wat is geweldloze communicatie? Wat is Verbindende communicatie? stappen geweldloze communicatie nonviolent communication model marshall rosenberg
"Mooie nieuwe inzichten die meteen toegepast kunnen worden! Boris is bekwaam en neemt je mee op reis om te kijken hoe jij je communicatie kan verbeteren met respect voor jezelf en de ander."
Onder begeleiding van Boris en Suzanne doken we als docententeam in de lagen onder onze gesprekken. Hun warme, scherpe en goed voorbereide aanpak maakte geweldloze communicatie voelbaar in plaats van theoretisch. Ze lieten ons ervaren hoe luisteren begrip wordt en hoe het uitspreken van gevoelens en behoeften helpt om te verbinden. Dankzij hun zorgvuldige voorbereiding en ervaring met groepsdynamica voelde iedereen zich vrij om zich uit te spreken en echt gehoord te worden. We gaan hier als team mee verder door middel van follow-up trainingen, om ons verder te verdiepen. Ik ben ervan overtuigd dat dit ons helpt om met meer aandacht en empathie samen te werken, in de dagelijkse drukte van de onderwijspraktijk.
"Wat een geweldige en intensieve dag. De Geweldloze Communicatie training heeft veel los gemaakt in het team en tot een hoop nieuwe inzichten geleid. Letterlijk elke 10 minuten waren goed besteed. Iedereen was erg tevreden aan het eind van de dag en ik heb alle vertrouwen dat het team de tools in handen heeft gekregen voor een nog betere samenwerking. Heb genoten! Heel veel dank Boris!"
Ik had vanuit mijn werk het geluk om de training Verbindende Communicatie van Boris te mogen volgen. Vanaf het eerste moment was ik aan! De combinatie van goed onderbouwde theorie en het direct toepassen in oefeningen en vervolgens in het ‘echte’ leven, hebben mij veel gebracht. Ik merk dat ik in gesprekken minder oordeel en steeds zoek naar mijn eigen behoefte, maar ook die van de ander. Dit levert naast interessante gesprekken ook meer rust en diepgang op in gesprek. Je merkt aan Boris dat hij verbindende communicatie ademt, wat inspireert en laat zien wat deze manier van communiceren doet in de praktijk. Door de veilige en open sfeer die wordt gecreëerd in de training, durf je jezelf open te stellen wat ervoor zorgt dat je ook écht leert. Kortom: Dikke aanrader!
"Een inspirerende dag bij Equanimity vol mooie inzichten welke je meteen kunt toepassen in je relaties, je werk, je leven. Het is bijzonder hoe Boris je deze inzichten laat ervaren met respect voor jezelf en de ander. Ik gun iedereen deze inzichten, deze training/cursus bij Boris. Een absolute aanrader dus!"
"De cursus Geweldloze Communicatie heeft mij geholpen meer bewust en empathisch te luisteren en reageren op anderen. Naar mijn mening één van de meest belangrijke skills voor effectief leiderschap op dit moment. Daarnaast is Boris een erg prettige trainer, die een veilige omgeving biedt om te leren."
"De training Geweldloze Communicatie gaf me veel eye-openers. Ik ben me sindsdien veel bewuster van de invloed die je houding en manier van formuleren hebben op hoe (en of) een ander naar je luistert. En andersom. Heel waardevol, zowel in mijn privé- als werkende leven. Daarnaast was het ook gewoon gezellig: Boris hield de sfeer er goed in met humor, openheid en improvisatievermogen."
"Recent heb ik bij Equanimity een introductiecursus gevolgd. Dat was een enorme eyeopener. Erg goed, persoonlijk en op passende schaal. Smaakt naar meer. Bij de komende gelegenheid wil ik een verdiepingsprogramma gaan volgen. Een echte aanrader."
"Onlangs basistraining geweldloze communicatie gevolgd bij Boris. Waardevolle, praktische handvatten geleerd voor het verbindend uiten van gevoelens en communiceren van behoeften. Leerzaam voor jong en oud."
Onlangs met ons team een training Verbindende Communicatie gevolgd bij Equanimity. Wat een waardevolle ervaring was dat! Trainer Boris wist een fijne, open sfeer te creëren en dankzij de verschillende werkvormen was de training niet alleen boeiend, maar ook praktisch toepasbaar. Een aanrader voor iedereen die op zoek is naar een interactieve en inspirerende training waarin je niet alleen leert, maar vooral ervaart hoe verbindende communicatie werkt. Dank je wel, Boris!
  • Stop polarisatie in je team

    Het structureel aanbieden van training in geweldloze communicatie in combinatie met gerichte inclusietraining is een succesvolle combinatie om polarisatie in teams tegen te gaan, zo betoogt Vivian Acquah van Amplify DEI.
    Lees verder
    Vivian Acquah over polarisatie Geweldloze communicatie en Inclusie
  • Geweldloos verzet en Geweldloze communicatie: moedig ouderschap in verbinding

    Geweldloos verzet en Verbindend gezag worden soms verward met Geweldloze of Verbindende communicatie. Dat is begrijpelijk, omdat beide benaderingen geworteld zijn in dezelfde principes van Nonviolence. Lees hier wat ze voor jou als ouder kunnen betekenen, en wat Equanimity hierover te bieden heeft.
    Lees verder
    geweldloos verzet en geweldloze communicatie verbindend gezag en verbindenden communicatie
  • Psychologische veiligheid in teams met Geweldloze communicatie

    In ieder team zijn er verschillen van mening, twijfels over besluiten, andere perspectieven, een gevoel dat er een betere oplossing mogelijk is. Of we ons wel of niet uitspreken op de werkvloer zegt veel over de cultuur van een team. Hebben we het idee dat onze input welkom is of houden we het voor ons?
    Lees verder
    hoe kan geweldloze communicatie bijdragen aan psychologische veiligheid
  • Geweldloosheid (Nonviolence) als ‘de derde weg’

    In dit artikel verken ik de betekenis van geweldloosheid als “de derde weg”. Geïnspireerd door het werk van Marshall Rosenberg, Mahatma Gandhi, Martin Luther King en Walter Wink kijken we naar geweldloosheid als een manier om actief op te komen voor rechtvaardigheid zonder de menselijkheid van de ander op te geven.
    Lees verder
    geweldloosheid de derde weg nonviolence as the third way
  • Empathie-valkuilen: waarom goedbedoelde reacties soms totaal niet helpen

    Wanneer je boos bent, ergens mee zit of iets verdrietigs hebt meegemaakt, hoop je op een empathische reactie van een ander. Toch is niet iedere reactie die je krijgt en die wellicht goed bedoeld is, ook daadwerkelijk helpend. Hoe komt dat?
    Lees verder
    de empathie valkuil
  • Conflict en de kunst van het verbinden

    Het vermogen om conflicten aan te gaan en op te lossen is één van de basispijlers van goed presterende teams. Maar hoe creëer je een duurzame cultuur die diversiteit omarmt en waar conflicten gezien kunnen worden als een weg naar verbinding, innovatie en vernieuwing?
    Lees verder
    conflict als kans voor verbinding
  • Baas in eigen oor: de vier manieren van luisteren in Geweldloze communicatie

    Wat we horen is in zekere zin een keuze. Door te leren herkennen welke oren we op hebben ontstaat er ruimte om bewust te kiezen hoe je gaat reageren. Binnen Geweldloze Communicatie worden verschillende manieren van luisteren onderscheiden waarmee je kunt oefenen.
    Lees verder
    empathisch luisteren als een giraf
  • Schaamte als sleutel naar verbinding

    Meestal zien we boosheid, schuld en schaamte als gevoelens waar we liever van af willen. We vinden ze ongemakkelijk, soms beschamend en dus duwen we ze weg - vaak al voordat we ons ervan bewust zijn dat we ze hebben. Maar wat nu als juist deze gevoelens de sleutels zijn naar verbinding?
    Lees verder
    schaamte en schuld
  • Balans in emotieregulatie: over het Gevaarsysteem, Jaagsysteem en Zorgsysteem

    Professor Paul Gilbert benadrukt dat een goede balans tussen drie emotieregulatie systemen essentieel is voor ons welzijn. Hoe kunnen Geweldloze communicatie en Mindfulness bijdragen aan deze balans?
    Lees verder
    Het Gevaarsysteem, het Jaagsystem en het Zorgsysteem. Emotieregulatie met Geweldloze communicatie en Mindfulness en compassie
  • “Hoezo geweldloos?” Over ‘Nonviolence’ in Geweldloze communicatie

    "Dat woord 'Geweldloos', ik weet het niet hoor, moeten we nou de hele tijd aardig tegen elkaar gaan doen ofzo?". Niet zelden hoor ik een variant op deze zin bij aanvang van een training bij een bedrijf of organisatie. Kennelijk roept het woord een allergische reactie bij sommige mensen op.
    Lees verder
    Nonviolence ahimsa geweldloosheid en geweldloze communicatie
  • Quasi-gevoelens en hoe ze bijdragen aan conflict en polarisatie

    Het uitspreken van je gevoelens kan erg opluchten en een verbindend effect hebben. Toch stuit je misschien ook wel eens op weerstand of irritatie. Hoe komt dat? De kans is groot dat je je hebt uitgesproken in quasi-gevoelens.
    Lees verder
    quasi emoties quasi gevoelens gedoelens
  • Gabor Maté over de mythe van normaal

    Iedereen verlangt naar verbinding, en soms is dit verlangen zo groot dat we onderweg onszelf verliezen. In zijn boek 'De mythe van normaal' laat arts en trauma-expert Gabor Maté zien hoe dat gebeurt en hoe we onze authenticiteit kunnen hervinden. Geweldloze Communicatie kan ons daarbij helpen.
    Lees verder
    gabor mate en geweldloze communicatie nonviolen communication
  • De Giraf en de Jakhals in Geweldloze communicatie

    De Giraf en de Jakhals worden in Verbindende / Geweldloze communicatie gebruikt als metafoor voor verschillende manier van denken en communiceren. De Jakhals staat daarbij voor denken en communiceren vanuit dominantie en onderwerping en de Giraf voor denken en communiceren vanuit compassie en zelfbewustzijn.
    Lees verder
    verschillende manieren van luisteren in geweldloze communicatie
  • Verbindende besluitvorming: Deep democracy en Geweldloze communicatie

    Waar Geweldloze communicatie zich met name richt op indivuele introspectie en interpersoonlijke dialoog, richt Deep Democracy zich meer op gespreksvoering en besluitvorming met groepen. In deze post vertel ik hoe Deep Democracy en Geweldloze communicatie elkaar kunnen aanvullen.
    Lees verder
    geweldloze communicatie in deep democracy
  • Waarom leuk werk je ziek kan maken

    Hoe komt het dat mensen met leuk of betekenisvol werk substantieel vaker 'omvallen'? Hoogleraar Media Studies Mark Deuze schreef er een boek over waarin hij uiteenzet waarom medewerkers uit de creatieve sector onevenredig veel te maken hebben met stress, burn-out en depressie.
    Lees verder
    stress en burnout in de creatieve sector

Blijf op de hoogte

Wil je op de hoogte wilt blijven van nieuwe trainingsdata en blogposts? Je ontvangt een paar keer per jaar een mail en je kunt je te allen tijde eenvoudig afmelden.

Emotionele intelligentie en psychologische veiligheid trainingen equanimity