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

Maple Ridge construction services

Construction Services Backed by Real Project Experience in Maple Ridge, BC

If you’re planning a construction project in Maple Ridge, VALROC offers hands-on experience, local knowledge, and a straightforward approach.

  • Proven work across residential, strata, and commercial properties in Maple Ridge
  • Experience with demolitions, renovations, foundations, garages, trenching, and paving
  • Free, no-obligation on-site estimates with open, transparent communication

Customer confidence

Why Maple Ridge customers can plan with confidence

Maple Ridge projects often require practical decisions around slopes, drainage, retaining, acreage access, and larger material movement before work begins.

What clients value

  • Insurance and liability coverage that helps protect the homeowner
  • Detailed contracts covering materials, payment schedules, walkthroughs, and warranties
  • Competitive pricing supported by coordinated scheduling and in-house services
  • One accountable contractor for communication, scheduling, trades, and project efficiencies
  • Reliable crews, consistent communication, and project accountability from start to finish

Planning shaped by Maple Ridge terrain and property conditions

Sloped lots, acreages, drainage routes, retaining needs, and variable access can change both the scope and sequence of construction in Maple Ridge. We assess those conditions before matching equipment and services to the work.

Customers receive a clearer plan for excavation, drainage, structures, concrete, asphalt, and material movement based on the property rather than a generic checklist.

Local construction planning

Construction support for Maple Ridge properties

Construction planning in Maple Ridge starts with the property, the municipal jurisdiction, and the practical conditions that affect approvals, access, sequencing, equipment, and material movement.

CONSTRUCTION SERVICE DIRECTORY

Browse construction services by category

Open the complete construction service hub, choose a service category, or go directly to a core service.

Decisions before construction

What we assess during a Maple Ridge on-site visit

A site conversation can identify alternatives before costs are committed, particularly where grades, drainage, excavation depth, hauling routes, neighbouring properties, and equipment access affect the plan.

01

Property and access

Review grades, drainage, excavation depth, hauling routes, neighbouring properties, and equipment access in relation to the result you want and the equipment or material movement the work may require.

02

City of Maple Ridge requirements

Identify likely City construction, development, permit, and demolition requirements, utility-locate responses, disposal requirements, and property-specific questions before finalizing the sequence.

03

Phasing around the property

Coordinate crews, deliveries, occupied areas, hauling, and site protection so the construction sequence reflects how this Maple Ridge property is actually used.

A practical route forward

How a Maple Ridge project moves from idea to construction

The exact sequence depends on the work and property. Early review of City of Maple Ridge requirements, access, disposal, equipment, and customer priorities helps turn an idea into a coordinated plan.

Confirm Maple Ridge requirements

Identify likely municipal permits, utility locates, disposal needs, technical details, and property-specific questions before work is scheduled.

Match equipment to the site

Coordinate machinery, hauling, materials, crews, and site protection around slopes, excavation depth, access, and staging space.

Construct and verify performance

Complete the agreed work in sequence, review drainage, grades, structures, and finished details, then provide a clear handoff.

Read the terrain and access

Review the intended result, grades, drainage paths, retaining needs, acreage access, existing services, and room for equipment.

What customers gain from the way we work

Customer benefits behind a well-planned Maple Ridge project

These advantages help customers evaluate more than a price, including project clarity, relevant experience, site coordination, in-house capability, and the way disruption will be managed.

Customer benefit icon

Expertise Built on Hundreds of Completed Projects

With a strong portfolio of completed work, our experience ensures high-quality craftsmanship and efficient project execution.

Customer benefit icon

Advanced Service Fleet & Specialized Equipment

Our extensive fleet of heavy-duty machinery, mobile service trucks, and specialized tools ensures unmatched efficiency and precision on every job site.

Customer benefit icon

Comprehensive Contracts – No Surprises, Just Clarity

Our contracts eliminate guesswork with clearly defined terms, pricing, timelines, and warranties, ensuring total transparency and peace of mind.

Customer benefit icon

A Reputation Built on Trust and Customer Satisfaction

Our reputation is built on trust, industry recognition, and strong professional relationships, ensuring confidence in every project we take on.

In-house capability

Equipment that supports construction work in Maple Ridge

Our Langley yard provides a base for selecting and staging equipment for Maple Ridge projects around access, excavation depth, hauling, material movement, compaction, and the actual scope of work.

John Deere excavator representing VALROC's compact to large excavator fleet.
Excavation and demolition site in Metro Vancouver with heavy machinery preparing for new construction.

Excavation fleet

Excavators matched to the site

Our in-house range includes compact machines for tight access, mid-size excavators for precise residential work, larger Deere excavators for deeper excavation and material handling, plus hydraulic breaker capability for concrete and rock removal.

  • Large, medium, small excavators
  • Demolition, Site preparation
  • Hydraulic hammers, crushers
  • Multiple attachments
Ammann ARX 2.1-2 and ARX 2-2 light tandem rollers featuring advanced articulation joints and electronic drive levers for precise asphalt and soil compaction.
Asphalt paving with a modern roller compactor in Metro Vancouver construction site.

Heavy Machinery & Earthmoving Equipment

Tandem Roller Compactor

Delivers smooth, even asphalt and soil compaction, improving surface durability and road longevity.

Heavy-duty flatbed service and delivery truck used for transporting equipment, towing gooseneck trailers, and carrying on-site fuel tanks.
Modern building renovation site in Vancouver featuring VALROC Development Ltd. truck for construction and building improvements.

Mobile Construction Equipped Service Vehicles

Flatbed Service & Delivery Truck

Facilitates equipment and material transport, allowing us to move multiple machines and long materials efficiently.

Wacker Neuson DT08 track dumper – compact 0.8-ton payload machine with hydrostatic drive and 79 cm width, ideal for confined construction sites.
Efficient street paving in Vancouver with Wacker Neuson mini dumper for smooth road construction.

Heavy Machinery & Earthmoving Equipment

Rubber Track Dumper

A compact, maneuverable track dumper that allows us to transport materials through tight spaces, improving site logistics and reducing manual labour.

International single-axle dump truck used for hauling materials, demolition debris, and construction site logistics.
Professional construction truck at VALROC Development Ltd. site in Metro Vancouver, showcasing quality renovation and development services.

Heavy Machinery & Earthmoving Equipment

Single Axle Dump Truck

A high-capacity hauler for transporting materials, debris, and equipment, streamlining job site cleanup and logistics.

Hino 198 box truck – a fully equipped 3-ton mobile service truck carrying essential contracting tools for concrete, asphalt, and carpentry work.
Reliable Vancouver-based construction and development services by Valroc Development Ltd. in Metro Vancouver.

Mobile Construction Equipped Service Vehicles

Fully Stocked Mobile Service Truck

Our fully equipped mobile service truck, essential for transporting contracting tools, materials, and heavy-duty equipment, ensuring on-site readiness and maximum efficiency.

John Deere 320D Skid Steer Loader with a 63 hp engine and 2,000 lbs operating capacity, ideal for versatile construction tasks.
Excavator working in a lush forested area for land clearing and excavation services.

Heavy Machinery & Earthmoving Equipment

Versatile Skid Steer Loader

A compact excavator with strong digging power, perfect for tight job sites requiring precision excavation.

Experience from local customers

Customer stories connected to Maple Ridge

Relevant experiences are presented as readable, image-led stories. Open a review only when you want the full detail.

Valroc owner and the Maple Ridge Recycling Facility chief operator walking the grounds with a recycling truck in the background.
Efficient waste management team working with recycling truck in Vancouver, BC. VALROC Metro Vancouver waste collection and disposal services.

We’ve been using Valroc for a number of years, services they performed on-site: many asphalt lot repairs, trenching for upgrading plant services, speed control – asphalt speed bumps, concrete slabs along with additional services like office renovations with updates and new walls and layout.

Ridge Meadows Recycling Society is a community-based, non-profit organization that advocates zero waste, operates responsible waste reduction services and provides environmental education. We employ people with developmental disabilities assisting their integration into the community.

To empower the residents of Maple Ridge to become interdependent stewards of the environment.
To operate an organization that offers as full a range of integrated, environmentally sound waste reduction services as possible.

It’s important to have community partners like VALROC, servicing our organizational needs. Ridge Meadows Recycling Society uses very heavy equipment around the recycling plant. This heavy duty equipment can have significant impact on surfaces, as they turn and move large amounts of inventory, creating wear and tear. Valroc has been exceptional to work with, they use quality materials, fast, easy to work around our schedules, they demonstrate compliance to safety protocol when on-site, we continue to use them as we feel that Valroc is a excellent contractor.

Thanks, VALROC Development Ltd.

★★★★★

Ridge Meadows Recycling Society, Up-grades, Asphalt Patch & Repair Services, Speed Bumps, Concrete Slab On Grade.

We've been using Valroc for a number of years, services they performed on-site: many asphalt lot repairs, trenching for upgrading plant services, speed control - asphalt speed bumps, concrete slabs along with additional services like office renovations with updates and new walls and layout. Ridge Meadows Recycling Society is a community-based, non-profit organization that advocates…

High-value planning information

Local resources for construction decisions

Verified municipal, utility, recycling, and disposal contacts for construction decisions in Maple Ridge. Use each section for a focused task, then confirm current requirements with the authority before acting.

Municipal information for construction planning in Maple Ridge, British Columbia.

Common local questions

Frequently asked questions for Maple Ridge

Open only the answer you need. These questions remain connected through the existing Location relationship.

Do I need a permit for a new driveway in Maple Ridge?

In Maple Ridge, a permit may be required for a new driveway depending on the project scope. If you are replacing an existing driveway with the same dimensions and materials, you may not need a permit. However, if you are expanding, changing the location, or modifying access points, a permit is likely required.

The City of Maple Ridge’s Engineering and Permits department oversees driveway applications. Homeowners must provide detailed site drawings showing property lines, drainage considerations, and driveway specifications.

Instead of navigating the permit process alone, VALROC Development Ltd. can handle all permitting and compliancerequirements for you. Our team has extensive experience working with Maple Ridge’s bylaws, ensuring that your driveway project meets all city regulations. Contact us for a free on-site consultation before reaching out to city officials.

Do I need a permit for a new driveway in Maple Ridge?

In Maple Ridge, a permit may be required for a new driveway depending on the project scope. If you are replacing an existing driveway with the same dimensions and materials, you may not need a permit. However, if you are expanding, changing the location, or modifying access points, a permit is likely required.

The City of Maple Ridge’s Engineering and Permits department oversees driveway applications. Homeowners must provide detailed site drawings showing property lines, drainage considerations, and driveway specifications.

Instead of navigating the permit process alone, VALROC Development Ltd. can handle all permitting and compliancerequirements for you. Our team has extensive experience working with Maple Ridge’s bylaws, ensuring that your driveway project meets all city regulations. Contact us for a free on-site consultation before reaching out to city officials.

What types of construction projects has VALROC completed in Maple Ridge?

VALROC Development Ltd. has provided comprehensive construction services throughout Maple Ridge, including:

Custom Home Builds

We have built luxury homes and custom-designed residences that meet modern energy efficiency standards, including projects in rural and urban settings.

Concrete & Asphalt Paving

From residential driveways to commercial parking lots, we offer durable concrete and asphalt solutions suited to Maple Ridge’s varied terrain and climate.

Excavation & Site Preparation

Our excavation team specializes in foundation digs, trenching, rock pits, and drainage system installations.

Retaining Walls & Drainage Solutions

Given Maple Ridge’s sloped landscapes, we have installed engineered retaining walls and perimeter drainage systemsto improve water flow and prevent erosion.

Commercial & Strata Property Maintenance

We have worked closely with local businesses and strata managers to provide infrastructure upgrades, property repairs, and regular maintenance services.

What types of construction projects has VALROC completed in Maple Ridge?

VALROC Development Ltd. has provided comprehensive construction services throughout Maple Ridge, including:

Custom Home Builds

We have built luxury homes and custom-designed residences that meet modern energy efficiency standards, including projects in rural and urban settings.

Concrete & Asphalt Paving

From residential driveways to commercial parking lots, we offer durable concrete and asphalt solutions suited to Maple Ridge’s varied terrain and climate.

Excavation & Site Preparation

Our excavation team specializes in foundation digs, trenching, rock pits, and drainage system installations.

Retaining Walls & Drainage Solutions

Given Maple Ridge’s sloped landscapes, we have installed engineered retaining walls and perimeter drainage systemsto improve water flow and prevent erosion.

Commercial & Strata Property Maintenance

We have worked closely with local businesses and strata managers to provide infrastructure upgrades, property repairs, and regular maintenance services.

How do I choose the right construction contractor in Maple Ridge?

When selecting a contractor, consider the following factors:

  • Experience & Track Record: Look for a company with a history of successful projects in Maple Ridge.
  • Licensing & Insurance: Ensure the contractor is fully licensed and insured to avoid liability issues.
  • Customer Reviews & Testimonials: A strong reputation among homeowners, businesses, and strata managers is a key indicator of quality.
  • Detailed Contracts & Transparent Pricing: Avoid vague estimates work with contractors who provide clear, itemized quotes.

At VALROC Development Ltd., we take pride in our long-standing reputation in Maple Ridge. We encourage clients to check our references and see why so many choose us for their construction projects.

How do I choose the right construction contractor in Maple Ridge?

When selecting a contractor, consider the following factors:

  • Experience & Track Record: Look for a company with a history of successful projects in Maple Ridge.
  • Licensing & Insurance: Ensure the contractor is fully licensed and insured to avoid liability issues.
  • Customer Reviews & Testimonials: A strong reputation among homeowners, businesses, and strata managers is a key indicator of quality.
  • Detailed Contracts & Transparent Pricing: Avoid vague estimates work with contractors who provide clear, itemized quotes.

At VALROC Development Ltd., we take pride in our long-standing reputation in Maple Ridge. We encourage clients to check our references and see why so many choose us for their construction projects.

What should I know before starting a construction project in Maple Ridge?

Before breaking ground, homeowners and businesses should:

  1. Understand local zoning and bylaws – Certain areas have restrictions on building height, lot coverage, and driveway access.
  2. Ensure necessary permits are obtained – Many projects require approval from the City of Maple Ridge before work can begin.
  3. Work with an experienced contractor – Hiring a full-service contractor like VALROC ensures your project remains compliant and on schedule.
  4. Plan for contingencies – Unexpected site conditions, weather delays, or material shortages can impact timelines.

By partnering with VALROC Development Ltd., you gain access to a team that handles everything from planning and permitting to construction and final inspections.

What should I know before starting a construction project in Maple Ridge?

Before breaking ground, homeowners and businesses should:

  1. Understand local zoning and bylaws – Certain areas have restrictions on building height, lot coverage, and driveway access.
  2. Ensure necessary permits are obtained – Many projects require approval from the City of Maple Ridge before work can begin.
  3. Work with an experienced contractor – Hiring a full-service contractor like VALROC ensures your project remains compliant and on schedule.
  4. Plan for contingencies – Unexpected site conditions, weather delays, or material shortages can impact timelines.

By partnering with VALROC Development Ltd., you gain access to a team that handles everything from planning and permitting to construction and final inspections.

How does zoning affect my construction project in Maple Ridge?

Zoning regulations dictate what you can build on your property. The City of Maple Ridge has zoning bylaws that outline:

  • Building setbacks (distance from property lines)
  • Maximum building heights
  • Land use restrictions (e.g., residential vs. commercial zones)
  • Environmental protection areas

Homeowners should check zoning designations before starting a project. VALROC’s team is highly experienced in navigating these regulations and can help you design a project that meets all city requirements.

How does zoning affect my construction project in Maple Ridge?

Zoning regulations dictate what you can build on your property. The City of Maple Ridge has zoning bylaws that outline:

  • Building setbacks (distance from property lines)
  • Maximum building heights
  • Land use restrictions (e.g., residential vs. commercial zones)
  • Environmental protection areas

Homeowners should check zoning designations before starting a project. VALROC’s team is highly experienced in navigating these regulations and can help you design a project that meets all city requirements.

What should I do if I have concerns during my construction project?

Effective communication is essential during construction. If you notice an issue, consider the following steps:

  • Document the concern with photos and notes.
  • Discuss it directly with the contractor to seek a resolution.
  • Ensure all agreements are in writing to avoid misunderstandings.

VALROC Development Ltd. encourages open, transparent communication throughout every project. Our clients appreciate our detailed project tracking, allowing them to stay informed and address concerns quickly.

What should I do if I have concerns during my construction project?

Effective communication is essential during construction. If you notice an issue, consider the following steps:

  • Document the concern with photos and notes.
  • Discuss it directly with the contractor to seek a resolution.
  • Ensure all agreements are in writing to avoid misunderstandings.

VALROC Development Ltd. encourages open, transparent communication throughout every project. Our clients appreciate our detailed project tracking, allowing them to stay informed and address concerns quickly.

How do I schedule an estimate for my construction project in Maple Ridge?

VALROC Development Ltd. offers free on-site consultations for all construction services in Maple Ridge. Scheduling is easy:

  1. Call or email us to discuss your project needs.
  2. We visit your site to assess the scope of work.
  3. You receive a detailed estimate, including materials, timeline, and pricing.

We make the process straightforward, ensuring you have all the information needed to make an informed decisionbefore construction begins.

How do I schedule an estimate for my construction project in Maple Ridge?

VALROC Development Ltd. offers free on-site consultations for all construction services in Maple Ridge. Scheduling is easy:

  1. Call or email us to discuss your project needs.
  2. We visit your site to assess the scope of work.
  3. You receive a detailed estimate, including materials, timeline, and pricing.

We make the process straightforward, ensuring you have all the information needed to make an informed decisionbefore construction begins.