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

HOLD THE GRADE WITH PURPOSE

Concrete Block Retaining Walls Built for Strength and Stability in Metro Vancouver

Heavy-duty retaining walls engineered for stability, drainage, and erosion control while enhancing property landscapes. A concrete block retaining wall can support a useful change in grade when its base, loading and water movement are planned together. VALROC reviews the slope and intended use before defining the wall system and construction scope.

Wall dimensions, engineering, drainage and adjacent work are confirmed for the property.

Hardscape construction with concrete block wall in Metro Vancouver, BC.
GROUND

Make sloped space usable

Plan the retained grade around access and the intended area behind the wall.

STRUCTURE

Build from the base up

Match excavation, compaction and block layout to the approved wall design.

WATER

Plan for drainage

Identify backfill and discharge paths before installing the wall.

FROM SLOPE TO STABLE WALL

How a concrete block retaining wall is built

Proper sub-base preparation, compaction, and drainage integration to prevent movement, erosion, and long-term failure. Engineered Systems, Built Right We install proper sub-base materials and compact each layer to ensure long-term stability and load-bearing performance. Block courses are laser-leveled, and in certain cases, tapered to increase drainage control and resist ground movement. The linked stages cover earthworks, block placement, drainage and detailing, then compacted backfill and final grading. Actual reinforcement, geogrid, permits and inspection requirements depend on height, loading and approved design.

  1. Compacting the sub-base to ensure a stable foundation for the retaining wall.

    Step 1

    Retaining Wall Excavation

    Site excavation, slope grading, and sub-base preparation for concrete block retaining walls, engineered to stabilize ground and support long-term wall performance.

    • Wall excavation
    • Subgrade preparation
    • Slope assessment
  2. Compacting backfill material to ensure wall stability.

    Step 2

    Retaining Wall Blocks

    Concrete blocks are installed using levelled courses, structural tie-backs, and custom elevations to retain grade and deliver clean, durable results.

    • Block courses
    • Wall alignment
    • Reinforcement layout
  3. Retaining wall installation using large concrete blocks with compact excavator on-site in North Vancouver, BC.

    Step 3

    Retaining Wall Detailing

    Finalizing retaining wall builds with precision cap stones, integrated drainage piping, fencing posts, and seamless surface transitions.

    • Drainage outlets
    • Wall caps
    • Surface transitions
  4. Finished result of a concrete brick wall after being installed in North Delta, BC

    Step 4

    Retaining Wall Finishing

    Completing retaining wall projects with precision backfill, landscape readiness, and full site clean-up by Valroc’s internal crews.

    • Compacted backfill
    • Final grading
    • Site cleanup

Hardscape Construction in Action, Maximize Potential

This video showcases VALROC’s hardscape construction projects across Metro Vancouver, including retaining walls, outdoor kitchens, patios, and structural security installations. Each installation reflects our in-house approach to excavation, concrete work, and integrated outdoor construction built for long-term durability and performance.

can you 

STRUCTURE MEETS PROPERTY USE

Choose the wall for the ground it retains

Engineered concrete block retaining walls built to control grade changes, support loads, and stabilize sloped terrain.

Durable, low-maintenance wall systems that improve safety, usability, and overall property longevity.

VALROC Development Ltd. designs and installs engineered concrete block retaining walls that provide long-term structural support, grade control, and aesthetic enhancement for residential, commercial, and light industrial properties across Metro Vancouver.

Smart Solutions for Challenging Terrain

Ideal for creating flat, useable land on sloped properties, helping homeowners maximize outdoor space.

Used in commercial and industrial projects to retain preload materials and support deep excavation zones.

Commonly installed for perimeter security, landscaping design, or to prevent erosion on unstable ground.

We help you create usable, beautiful outdoor space while improving the safety and longevity of your property.

Concrete block retaining walls can manage grade changes near yards, access routes and building areas. Wall height, soil, nearby loads and water conditions determine whether a proposed block system is suitable and what engineering is needed.

GRADE

Define the retained height

Measure the elevation change and intended use of each level.

BASE

Prepare stable support

Review excavation depth, bearing conditions and base compaction.

DRAINAGE

Give water a route

Plan backfill, outlets and discharge for the site.

FINISH

Connect the wall edges

Coordinate caps, stairs and nearby surfaces when included.

SELECT FOR THE SITE

Block wall decisions that shape the result

Choose the block style, wall alignment, stepped elevations and cap details around the site grade and intended use. Drainage, reinforcement, fencing and adjacent landscape work are coordinated with the approved wall design.

Concrete block retaining wall construction support

Included in our service:

  • • Wall location and grade review

  • • Excavation and reinforced base preparation

  • • Block style and wall layout coordination

  • • Drain rock and wall drainage installation

  • • Geogrid reinforcement when required

  • • Step, fence and landscape interface planning

  • • Material ordering from established suppliers

  • • Equipment access and site protection

  • • Permit or engineering coordination when required

  • • Final grade review and project walkthrough

Block size, wall alignment, stepped courses, cap details and drainage arrangements can vary by project. Structural reinforcement and adjacent features must follow the approved design and be included in the written scope.

Keep selections tied to the design

PLAN THE INTERFACES

Coordinate the wall with surrounding property work

A retaining wall may form an edge for a driveway, patio, stairs or garden level. Excavation, drainage and surface grades should be coordinated, but each adjacent Service requires its own agreed scope.

Driveways, patios, fencing, landscape planting and offsite drainage connections are not automatic block wall inclusions.

  • Excavation site preparation with John Deere excavator and laser rotary measurement tool in use

    Site preparation for concrete block retaining walls

    • Block wall site preparation
    • Wall base
    • Grade preparation

    Block retaining walls need a suitable work area, prepared base and controlled surrounding grades. Early site preparation helps establish the wall line, material access and space for drainage behind the wall.

    Explore site preparation services
  • Valroc excavators clearing residential demolition debris in Metro Vancouver

    Excavation for concrete block retaining walls

    • Block wall excavation
    • Retaining wall base
    • Slope work

    Excavation creates the wall bench, base elevation and room for drainage aggregate. Coordinating machine access and soil removal can make block wall construction more efficient on sloped properties.

    Explore excavation and machine services
  • To catch basins tied into perimeter drainage system on a new build that was done with Valroc as the contractor in Burnaby Canada

    Drainage behind concrete block retaining walls

    • Block wall drainage
    • Drain rock
    • Water pressure

    Water pressure can affect retaining wall performance and the areas around it. Drain pipe, clear aggregate and an appropriate outlet help move water from behind the block wall.

    Explore perimeter drainage systems
  • Man working on staircase construction in Vancouver, BC, residential project, building new wooden steps.

    Concrete steps through block retaining walls

    • Retaining wall steps
    • Terrace access
    • Grade transition

    Steps can provide direct access between terraces created by a concrete block retaining wall. Coordinating the stair width, landings and wall geometry creates a safer and more intentional grade transition.

    Explore concrete steps and staircases
  • Reinforcing steel for concrete patio installation in Vancouver.

    Concrete patios supported by block retaining walls

    • Patio retaining wall
    • Level outdoor space
    • Backyard terrace

    A concrete block retaining wall can help create level space for a patio on a sloped yard. Wall height, drainage and the supported patio area should be considered together before construction.

    Explore concrete patio installation

DOCUMENTED EXPERIENCE

Concrete block retaining wall experience across Metro Vancouver

VALROC builds concrete block retaining walls for grade changes, property support and usable outdoor space across Metro Vancouver. Our experience helps connect wall layout, excavation, drainage and surrounding hardscape to the actual site conditions. Our crews have completed retaining and hardscape work throughout Langley, Cloverdale, South Surrey, White Rock, Burnaby and Coquitlam, with local experience navigating access, drainage, engineering and municipal requirements.

DEFINE THE OUTDOOR SCOPE

Discuss a block retaining wall proposal

Share the property, intended use and available plans with VALROC. An onsite review can establish what work is required before a concrete block retaining wall proposal is prepared.

  • Share the project

    Explain the site, intended use and known constraints.

  • Review the property

    Review the slope, soil, existing structures, access, wall height, surcharge loads and water paths before recommending a concrete block retaining wall.

  • Confirm the proposal

    Compare included work, selections and boundaries in writing.

  • What affects a concrete block retaining wall estimate?

    Wall length and height, access, soil, excavation, block system, reinforcement, drainage, permits and finishing details affect the proposal. A property review is needed before providing a specific price.

    What affects a concrete block retaining wall estimate?

    Wall length and height, access, soil, excavation, block system, reinforcement, drainage, permits and finishing details affect the proposal. A property review is needed before providing a specific price.

    Request Your Free On-site Estimate

    REVIEW THE SITE CONDITIONS

    Assess the ground before planning the wall

    Review the slope, soil, existing structures, access, wall height, surcharge loads and water paths before recommending a concrete block retaining wall.

  • 01

    Define the intended use

    Explain what the completed outdoor space must support.

  • 02

    Review the property

    Review the slope, soil, existing structures, access, wall height, surcharge loads and water paths before recommending a concrete block retaining wall.

  • 03

    Identify approvals

    Check drawings, permits and inspection responsibilities for the proposed work.

  • 04

    Write the boundaries

    Record included systems, finishes and separately scoped work.

  • What needs confirmation

    A wall near a driveway, building or property boundary may need engineering, permits or separate geotechnical input. Surface water cannot be directed to an unapproved discharge point.

    What needs confirmation

    A wall near a driveway, building or property boundary may need engineering, permits or separate geotechnical input. Surface water cannot be directed to an unapproved discharge point.

    ANSWERS REQUIRE SITE CONTEXT

    Questions about concrete block retaining walls

    The linked questions cover wall types, structural performance, drainage, materials and permits. Answers require the actual loads, ground conditions and local approval rules.

    What are concrete block retaining walls, and why are they used?

    Concrete block retaining walls are engineered structures used to hold back soil, manage elevation changes, and stabilize sloped ground.

    • Preventing soil movement and erosion on sloped properties.
    • Creating level areas for patios, driveways, or building pads.
    • Supporting roadways, access lanes, or structural loads.
    • Managing surface water and reducing washouts.
    • Providing a durable, finished edge for landscaping.

    When designed and built correctly, they provide long-term structural stability and predictable performance.

    What are concrete block retaining walls, and why are they used?

    Concrete block retaining walls are engineered structures used to hold back soil, manage elevation changes, and stabilize sloped ground.

    • Preventing soil movement and erosion on sloped properties.
    • Creating level areas for patios, driveways, or building pads.
    • Supporting roadways, access lanes, or structural loads.
    • Managing surface water and reducing washouts.
    • Providing a durable, finished edge for landscaping.

    When designed and built correctly, they provide long-term structural stability and predictable performance.

    What types of concrete block retaining walls does VALROC build?

    Retaining wall systems are selected based on site conditions, height, and loading requirements.

    • Gravity walls relying on block mass.
    • Segmental retaining walls with interlocking blocks.
    • Reinforced systems using geogrid or steel.
    • Structural retaining walls with concrete footings.
    • Terraced wall systems for stepped grade changes.

    The appropriate system is determined during site assessment and planning.

    What types of concrete block retaining walls does VALROC build?

    Retaining wall systems are selected based on site conditions, height, and loading requirements.

    • Gravity walls relying on block mass.
    • Segmental retaining walls with interlocking blocks.
    • Reinforced systems using geogrid or steel.
    • Structural retaining walls with concrete footings.
    • Terraced wall systems for stepped grade changes.

    The appropriate system is determined during site assessment and planning.

    How does VALROC ensure the strength and longevity of retaining walls?

    Wall performance depends on correct preparation, materials, and installation methods.

    • Excavating and compacting a stable base.
    • Using properly rated concrete block systems.
    • Incorporating reinforcement when required by height or load.
    • Following engineered installation standards.
    • Maintaining accurate alignment and leveling.

    Each wall is built to suit site conditions rather than relying on a one-size-fits-all approach.

    How does VALROC ensure the strength and longevity of retaining walls?

    Wall performance depends on correct preparation, materials, and installation methods.

    • Excavating and compacting a stable base.
    • Using properly rated concrete block systems.
    • Incorporating reinforcement when required by height or load.
    • Following engineered installation standards.
    • Maintaining accurate alignment and leveling.

    Each wall is built to suit site conditions rather than relying on a one-size-fits-all approach.

    What are the advantages of using concrete block retaining walls over other materials?

    Concrete block retaining walls are commonly chosen for their strength, durability, and predictable behavior over time.

    • Resist rot, decay, and insect damage.
    • Handle higher soil pressure and load conditions.
    • Require minimal ongoing maintenance.
    • Offer consistent dimensions and interlocking systems.
    • Provide long service life when properly installed.

    They are well suited for both functional and structural retaining applications.

    What are the advantages of using concrete block retaining walls over other materials?

    Concrete block retaining walls are commonly chosen for their strength, durability, and predictable behavior over time.

    • Resist rot, decay, and insect damage.
    • Handle higher soil pressure and load conditions.
    • Require minimal ongoing maintenance.
    • Offer consistent dimensions and interlocking systems.
    • Provide long service life when properly installed.

    They are well suited for both functional and structural retaining applications.

    Do concrete block retaining walls require permits?

    Permit requirements depend on wall height, location, and loading conditions.

    • Short landscape walls may not require permits.
    • Taller walls typically require engineering review.
    • Walls supporting driveways or structures usually require approval.
    • Walls near property lines or public areas may trigger additional review.

    Permit requirements are confirmed during planning so work proceeds without compliance issues.

    Do concrete block retaining walls require permits?

    Permit requirements depend on wall height, location, and loading conditions.

    • Short landscape walls may not require permits.
    • Taller walls typically require engineering review.
    • Walls supporting driveways or structures usually require approval.
    • Walls near property lines or public areas may trigger additional review.

    Permit requirements are confirmed during planning so work proceeds without compliance issues.

    How does VALROC incorporate drainage solutions into retaining walls?

    Drainage is a critical part of retaining wall performance and is addressed during design and construction.

    • Installing granular drainage backfill behind the wall.
    • Using perforated drain pipe to move water away from the structure.
    • Including drainage outlets or relief points where required.
    • Separating soil from drainage zones with filter fabric.

    Proper drainage reduces pressure buildup and helps prevent long-term wall movement.

    How does VALROC incorporate drainage solutions into retaining walls?

    Drainage is a critical part of retaining wall performance and is addressed during design and construction.

    • Installing granular drainage backfill behind the wall.
    • Using perforated drain pipe to move water away from the structure.
    • Including drainage outlets or relief points where required.
    • Separating soil from drainage zones with filter fabric.

    Proper drainage reduces pressure buildup and helps prevent long-term wall movement.

    Why choose VALROC Development Ltd. for your concrete block retaining wall?

    Retaining walls require coordination between excavation, drainage, and structural installation.

    • Experience with residential, commercial, and industrial sites.
    • In-house excavation, grading, and compaction capability.
    • Understanding of drainage and soil behavior.
    • Ability to work with engineered drawings when required.
    • Single contractor responsibility from start to finish.

    This integrated approach reduces risk and improves long-term results.

    Why choose VALROC Development Ltd. for your concrete block retaining wall?

    Retaining walls require coordination between excavation, drainage, and structural installation.

    • Experience with residential, commercial, and industrial sites.
    • In-house excavation, grading, and compaction capability.
    • Understanding of drainage and soil behavior.
    • Ability to work with engineered drawings when required.
    • Single contractor responsibility from start to finish.

    This integrated approach reduces risk and improves long-term results.

    METRO VANCOUVER HARDSCAPE

    Block retaining wall projects across Metro Vancouver

    VALROC installs concrete block retaining walls from its Langley construction yard, supporting grade changes, garden areas, driveways and usable outdoor space across local residential and strata properties. Wall alignment, excavation, reinforced base preparation, block delivery and drainage are coordinated around the slope and adjoining surfaces.

    Properties in Surrey, White Rock and Burnaby can require stepped walls, restricted access or connections to stairs and fencing, while Delta projects may place added focus on drainage and finished grades. Each wall is matched to the site conditions and approved design.