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

EQUIPMENT AND OPERATORS FOR THE TASK

Professional Excavation, Trucking & Machine Service.

At VALROC Development Ltd., we offer two flexible approaches to excavation and site-work services across Metro Vancouver: Hourly excavation, trucking, and machine services for homeowners, contractors, and trades needing skilled operators and equipment support on demand. Full-scope excavation and site preparation packages for larger projects requiring planning, engineering, permits, project management, and complete execution. Whether you need a machine and operator for a few hours or a fully managed excavation project from start to finish, our team provides the equipment, experience, and support to help move your project forward safely and efficiently. Book an operator and suitable equipment for a defined task, or plan a larger excavation package with VALROC. The work, mobilization and customer responsibilities are confirmed before equipment arrives.

Hourly support and managed excavation are separate ways to scope the work.

Valroc excavators clearing residential demolition debris in Metro Vancouver
MACHINE CHOICE

Match equipment to the task

Review access, reach and material movement before selecting a machine.

OPERATOR SUPPORT

Work with a skilled operator

Keep the equipment task and onsite direction clear from the start.

PROJECT SCOPE

Choose hourly or managed work

Define whether VALROC supplies a machine phase or coordinates a larger excavation package.

HOW THE WORK PROCEEDS

How excavation and machine service is planned and carried out

The connected records explain hourly mobilization, machine booking policy and the value of operator supported service. They are not a fixed excavation sequence for every property.

  1. Hauling material from excavation site

    Step 1

    Hourly Excavation Services

    Flexible, hourly excavation and trucking support, professional operators, no rental hassle, perfect for homeowners, trades, and strata clients.

    • Machine booking
    • Operator support
    • Site access
  2. Compact excavation in tight access area

    Step 2

    Hourly Equipment Services

    On-site equipment deployment, transport, and execution by the hour, extendable as needed, perfect for flexible project support.

    • Hourly equipment
    • Mobilization
    • Booking scope
  3. Structure demolition contractor at work

    Step 3

    Hourly Machine Services

    Learn why our flexible, operator-included solution often delivers better value with less risk.

    • Operator expertise
    • Equipment choice
    • Project control

Video, Excavation, Demolition & Site Preparation Overview

A project compilation showing VALROC Development Ltd. performing excavation, demolition, trucking, grading, drainage preparation, asphalt removal, and site preparation services across Metro Vancouver and the Fraser Valley.

can you 

MATCH THE WORK TO THE SITE

Where excavation and machine service fits

Whether you need an excavator and operator for a few hours, trucking support for material removal, grading assistance, trenching services, or complete site preparation for a custom home or commercial project, VALROC provides experienced crews, specialized equipment, and practical construction solutions designed to keep your project moving safely and efficiently.

Licensed operators

Specialized construction machinery

Real-world site experience

Full insurance coverage and safety protocols

Unlike traditional equipment rentals, VALROC provides both the machine and the experienced operator, helping reduce project delays, safety risks, equipment damage, and costly mistakes caused by inexperience or changing site conditions.

Excavators, trucks and other machinery can support grading, material movement, site cleanup and defined excavation tasks. A larger site preparation package may require separate planning, design and coordination.

HOURLY SUPPORT

Bring in the right machine

Use operator supported equipment for a defined phase.

TRUCKING

Plan material movement

Confirm what is hauled, delivered or disposed of in the booking.

ACCESS

Assess the work area

Check entry width, ground conditions and nearby services.

MANAGED SCOPE

Coordinate larger excavation

Define plans, milestones and handoff responsibilities in a separate proposal.

DEFINE THE CONTRACTED TASK

Scope choices for excavation and machine service

Choose hourly equipment and operator support for a defined task, or a managed excavation package for work requiring planning, trucking, materials and coordinated site preparation.

Machine size, access, disposal and the required finished grade determine the appropriate service.

Excavation, trucking and machine service support

Included in our service:

  • • Site review and access planning

  • • Utility information reviewed before digging

  • • Excavation completed to the required grades

  • • Organized trucking and material movement

  • • Specialized machines selected for the site

  • • Soil, rock and aggregate placement coordinated

  • • Work areas managed around occupied properties

  • • Progress communication through each work stage

  • • Final grading and site cleanup

Choose a defined hourly machine task or a separately proposed managed excavation package. Equipment size, trucking, mobilization, materials and disposal depend on the actual work order.

Coordinate the task and the handoff

COORDINATE THE NEXT PHASE

Coordinate excavation and machine service with adjacent work

Machine service can support foundation excavation, drainage trenching, site preparation or material hauling. Those are distinct project scopes, even when the same crew and equipment help complete them.

Utility installation, engineered design, permits, material supply, disposal and final restoration are not automatic parts of an hourly machine booking.

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

    Excavation and machine support for site preparation

    • Site preparation equipment
    • Excavation support
    • Material handling

    Site preparation often depends on the right machines for clearing, grading, aggregate placement and material handling. Coordinating equipment and trucking helps turn an undeveloped or congested area into a workable construction site.

    Explore site preparation services
  • Workers performing trench excavation with shovels on construction site

    Machine excavation for trenching services

    • Machine trenching
    • Utility excavation
    • Soil handling

    Utility and drainage trenches vary in depth, width and access. Selecting suitable excavation equipment can improve production while supporting cleaner trench lines and controlled soil handling.

    Explore trenching services
  • Wood footings a top of hard packed subbase and just starting to build foundational walls

    Excavation for foundations and footings

    • Foundation excavation
    • Footing dig
    • Building excavation

    Foundation excavation creates the working area and bearing elevations for concrete footings and walls. Machine work, trucking and concrete scheduling can be coordinated to keep the building excavation moving.

    Explore foundations and footings
  • A freshly stripped concrete retaining wall at a luxury residential build in Brookswood, Langley, BC, showing the VALROC excavator and crew preparing the drainage trench behind the wall.

    Excavation for engineered concrete retaining walls

    • Retaining wall excavation
    • Slope grading
    • Wall footing

    Retaining wall construction may require slope excavation, footing preparation and room for drainage aggregate. Coordinated machine access helps shape the wall area and manage excavated material safely.

    Explore engineered concrete retaining walls
  • To catch basins tied into perimeter drainage system on a new build that was done with Valroc as the contractor in Burnaby Canada

    Excavation for perimeter drainage installation

    • Drainage excavation
    • Foundation access
    • Perimeter drain

    Perimeter drainage work often requires controlled excavation beside foundations and around existing improvements. The machine plan can account for depth, soil storage and restoration of access areas.

    Explore perimeter drainage systems
  • Luxury custom home build with lots of amazing features, showing a construction sign of Valroc Development Ltd. showing it's thier construction site

    Excavation and trucking for custom home builds

    • Custom home excavation
    • Construction trucking
    • Site grading

    Custom home construction generates excavation, aggregate and hauling needs throughout the project. Coordinating machines and trucking with the build schedule supports foundations, services, grading and exterior work.

    Explore custom home construction

DOCUMENTED EXPERIENCE

Excavation and machine service experience across Metro Vancouver

VALROC supports residential, strata, commercial and light industrial projects with excavation, trucking and machine services across Metro Vancouver. Our crews understand how access, soil conditions, utilities and the next stage of construction affect the work. Our Langley construction yard supports efficient mobilization into Surrey, Burnaby, Coquitlam, Maple Ridge and Vancouver, with experience coordinating access, municipal requirements and other construction professionals.

DEFINE THE WORK BEFORE BOOKING

Discuss your excavation and machine service proposal

Share your plans, photos and work goals with VALROC. An onsite review can establish equipment needs, access and the limits of an excavation and machine service scope.

  • Share the task

    Explain the planned excavation, site access and available drawings.

  • Review the property

    Describe the excavation task, access route, existing services, ground conditions, material handling and who will direct the work onsite.

  • Confirm the arrangement

    Review equipment, materials, timing and handoff in the written scope.

  • What affects an excavation and machine service estimate?

    Machine type, hours, transport, access, operator needs, materials and disposal affect the price. Larger managed work also depends on plans and site conditions. A current site review is needed for a property specific price.

    What affects an excavation and machine service estimate?

    Machine type, hours, transport, access, operator needs, materials and disposal affect the price. Larger managed work also depends on plans and site conditions. A current site review is needed for a property specific price.

    Request Your Free On-site Estimate

    CHECK THE ACTUAL CONDITIONS

    Assess the site before excavation and machine service

    Describe the excavation task, access route, existing services, ground conditions, material handling and who will direct the work onsite.

  • 01

    Define the task

    Describe the excavation task, access route, existing services, ground conditions, material handling and who will direct the work onsite.

  • 02

    Review access

    Check machine access, adjacent structures and the work area.

  • 03

    Check known services

    Confirm available locate information and any excavation constraints.

  • 04

    Write the scope

    Specify machine work, material handling and handoff responsibilities.

  • What the surface cannot show

    Equipment choice can change when buried services, unsuitable ground or restricted access become apparent. Any expansion of work needs a revised scope.

    What the surface cannot show

    Equipment choice can change when buried services, unsuitable ground or restricted access become apparent. Any expansion of work needs a revised scope.

    ANSWERS NEED PROJECT CONTEXT

    Questions about excavation and machine service

    The linked questions explain hourly versus managed work, equipment choices, insurance and trade support. Actual rates, minimums and availability require a current booking confirmation.

    Do you offer hourly excavation and machine services or full contracts?

    We offer both hourly machine services and larger scoped work.

    • Hourly excavator, truck, or compactor services.
    • Short-term or single-day machine support.
    • Multi-day or phased work without long-term commitment.
    • Clear billing based on time and equipment used.

    This gives flexibility for homeowners, trades, and contractors alike.

    Do you offer hourly excavation and machine services or full contracts?

    We offer both hourly machine services and larger scoped work.

    • Hourly excavator, truck, or compactor services.
    • Short-term or single-day machine support.
    • Multi-day or phased work without long-term commitment.
    • Clear billing based on time and equipment used.

    This gives flexibility for homeowners, trades, and contractors alike.

    Can I hire just an excavator and operator for a small job?

    Yes. You can hire a single machine with an experienced operator for short or small-scope work.

    • Trenching for utilities or drainage.
    • Light demolition or concrete removal.
    • Grading, leveling, or backfilling.
    • Access-limited or residential work.

    We match the machine size to the task so the work is efficient and appropriate for the site.

    Can I hire just an excavator and operator for a small job?

    Yes. You can hire a single machine with an experienced operator for short or small-scope work.

    • Trenching for utilities or drainage.
    • Light demolition or concrete removal.
    • Grading, leveling, or backfilling.
    • Access-limited or residential work.

    We match the machine size to the task so the work is efficient and appropriate for the site.

    What types of excavation and machine work do you provide?

    We provide a full range of excavation and machine services to support residential, commercial, and light industrial projects.

    • General excavation and site grading.
    • Trenching for drainage, plumbing, and electrical services.
    • Concrete breaking, removal, and disposal.
    • Structural backfilling and compaction.
    • Material import and export, including gravel, sand, and engineered fill.
    • Compaction using steel-drum rollers, plate compactors, or rammers.
    • Tight-access excavation using compact and low-impact equipment.

    For unusual site conditions or specialized work, we match the right equipment and experienced operators to the task.

    What types of excavation and machine work do you provide?

    We provide a full range of excavation and machine services to support residential, commercial, and light industrial projects.

    • General excavation and site grading.
    • Trenching for drainage, plumbing, and electrical services.
    • Concrete breaking, removal, and disposal.
    • Structural backfilling and compaction.
    • Material import and export, including gravel, sand, and engineered fill.
    • Compaction using steel-drum rollers, plate compactors, or rammers.
    • Tight-access excavation using compact and low-impact equipment.

    For unusual site conditions or specialized work, we match the right equipment and experienced operators to the task.

    Can I mix and match services like getting gravel delivered one day and excavation the next?

    Yes. Our services are flexible and can be scheduled in stages.

    • Material delivery without machine work.
    • Excavation or trenching on a later date.
    • Compaction or finishing work as a separate visit.
    • Adjusting timing based on site readiness.

    This allows projects to move at a pace that works for you.

    Can I mix and match services like getting gravel delivered one day and excavation the next?

    Yes. Our services are flexible and can be scheduled in stages.

    • Material delivery without machine work.
    • Excavation or trenching on a later date.
    • Compaction or finishing work as a separate visit.
    • Adjusting timing based on site readiness.

    This allows projects to move at a pace that works for you.

    Do you provide equipment for tight-access or compact sites?

    Yes. We operate compact equipment designed for restricted access areas.

    • Mini excavators with retractable tracks.
    • Low-impact machines for residential properties.
    • Backyard, side-yard, and urban access solutions.
    • Reduced disturbance to existing landscaping.

    This allows work to be completed where full-size equipment cannot access.

    Do you provide equipment for tight-access or compact sites?

    Yes. We operate compact equipment designed for restricted access areas.

    • Mini excavators with retractable tracks.
    • Low-impact machines for residential properties.
    • Backyard, side-yard, and urban access solutions.
    • Reduced disturbance to existing landscaping.

    This allows work to be completed where full-size equipment cannot access.

    Are your operators insured while working on my property?

    Yes. All operators and machines are fully insured while on site.

    • WorkSafeBC coverage for all operators.
    • $5 million general liability insurance.
    • Regular safety training and site awareness.
    • Equipment maintained to operational standards.

    This protects both the property owner and the work being performed.

    Are your operators insured while working on my property?

    Yes. All operators and machines are fully insured while on site.

    • WorkSafeBC coverage for all operators.
    • $5 million general liability insurance.
    • Regular safety training and site awareness.
    • Equipment maintained to operational standards.

    This protects both the property owner and the work being performed.

    Can you help me figure out what machinery I actually need for my project?

    Yes. Part of our role is helping you choose the right equipment for the job.

    • Reviewing the scope and site conditions.
    • Matching machine size to access and workload.
    • Recommending attachments or support equipment if needed.
    • Adjusting equipment as the project progresses.

    This helps avoid overbuilding, delays, or unnecessary cost.

    Can you help me figure out what machinery I actually need for my project?

    Yes. Part of our role is helping you choose the right equipment for the job.

    • Reviewing the scope and site conditions.
    • Matching machine size to access and workload.
    • Recommending attachments or support equipment if needed.
    • Adjusting equipment as the project progresses.

    This helps avoid overbuilding, delays, or unnecessary cost.

    I’m a trades contractor can I hire Valroc just to assist with a specific phase of my job?

    Yes, we regularly support electricians, plumbers, landscapers, and other trades who need trenching, pad prep, backfill, or debris removal. Our hourly machine services let you stay focused on your trade while we handle the heavy lifting. You’ll get a dependable operator who works efficiently and respects your job-site.

    I’m a trades contractor can I hire Valroc just to assist with a specific phase of my job?

    Yes, we regularly support electricians, plumbers, landscapers, and other trades who need trenching, pad prep, backfill, or debris removal. Our hourly machine services let you stay focused on your trade while we handle the heavy lifting. You’ll get a dependable operator who works efficiently and respects your job-site.

    METRO VANCOUVER GROUNDWORK

    Property specific excavation and machine service across Metro Vancouver

    VALROC coordinates excavation, trucking and machine service from its Langley construction yard, where equipment, attachments and haul scheduling can be matched to the work. Projects across Langley and Surrey include trenching, grading, material removal, foundation excavation and site preparation for residential, strata and business properties.

    Excavation in Burnaby may require compact equipment and careful access planning, while work in Delta can place greater emphasis on drainage grades, material movement and ground conditions. The machine, trucking plan and finished elevation are selected for the actual site.