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

CONCRETE SIDEWALK INSTALLATION

Precision Concrete Sidewalk Installation in Metro Vancouver

Durable, slip-resistant concrete sidewalks designed for safety, longevity, and compliance with accessibility standards.

A defined walkway route, grades and finish for the people who use the property.

Sidewalk leading up to the front door through engineered concrete walls. The sidewalk still have the wooden forms as they are freshly poured with concrete.
WALKING SURFACE

Plan a usable route

Properly graded concrete sidewalks built for safety, accessibility, and long-term durability.

GROUND PREPARATION

Address grade and water

Precision subgrade preparation and drainage control to prevent cracking, washout, and water issues.

PROPERTY CONNECTIONS

Meet the adjacent spaces

Code-conscious installations that integrate cleanly with entrances, driveways, and surrounding landscapes.

FROM ROUTE TO FINISH

How a concrete sidewalk is built

Each sidewalk begins with the existing route and site conditions. Removal, grading, forming, any specified reinforcement, placement and finishing must be coordinated with pedestrian access and water movement.

  1. Ongoing sidewalk prep work during the demolition & removal stage at residential property

    Step 1

    Concrete Sidewalk Demolition

    We handle sidewalk demolition with efficiency and care, using specialized machinery and experienced crews to safely break and remove deteriorated concrete, minimizing disruption and maximizing value.

    • Sidewalk removal
    • Existing concrete
    • Access protection
  2. Belmont team member using flat plate tamper for subbase materials before pouring concrete sidewalks

    Step 2

    Concrete Sidewalk Site Prep

    We prepare sidewalk sites for long-term durability—grading, compacting, and planning layout for drainage, accessibility, and custom features like lighting or landscaped borders.

    • Subgrade preparation
    • Walkway grading
    • Drainage layout
  3. VALROC team building onsite custom wood forms for a concrete sidewalk installation

    Step 3

    Concrete Sidewalk Formwork

    Precision sidewalk layout and formwork using rotary lasers, engineered slopes, and durable materials — ready to tie into drains, foundations, and accessibility upgrades.

    • Sidewalk formwork
    • Entrance elevations
    • Walkway layout
  4. VALROC team member installing rebar into a sidewalk that is between a residential home and newly constructed garage located in Langley British Columbia

    Step 4

    Concrete Sidewalk Reinforcement

    We reinforce sidewalks with properly positioned rebar, tied into existing footings, foundations, or engineered retaining walls for long-lasting strength and slope stability.

    • Specified reinforcement
    • Concrete rebar
    • Structural interfaces
  5. Finish edging troweling on a concrete sidewalk alongside a newly installed detached garage garage

    Step 5

    Concrete Sidewalk Placement

    We carefully pour and finish your concrete sidewalks with precision—offering multiple finish types to suit safety, design, and functional needs. Final grades, weather, and methods are professionally assessed to ensure lasting quality.

    • Sidewalk placement
    • Surface texture
    • Finished grades

Concrete Sidewalks, Walkways and Entryways

Explore VALROC sidewalk projects across Metro Vancouver, from replacement walkways to custom pathways connecting driveways, stairs and outdoor spaces.

can you 

SIDEWALK ACCESS THAT FITS THE SITE

Safe, Attractive & Long-Lasting Concrete Sidewalk Solutions

VALROC Development Ltd. installs expertly graded, long-lasting sidewalks for residential, strata, and commercial properties throughout Metro Vancouver. While often underestimated, sidewalks require technical precision to ensure they are both functional and protective of the surrounding property.

A well-built concrete sidewalk does more than create a path from one point to another. It improves safety, enhances curb appeal, protects surrounding property, and provides long-term accessibility for residents, visitors, customers, and tenants.

Whether you’re installing a new sidewalk for a residential property, replacing a deteriorated walkway in a strata complex, or improving access around a commercial building, VALROC Development Ltd. provides complete design and installation services tailored to your property’s needs.

Accessibility-conscious designs for improved mobility

The route is planned around the people using it, adjacent grades and the property features it must connect. The design and any accessibility requirements are confirmed for the specific site.

ACCESS

A practical walking route

Plan the sidewalk width, alignment and entrance connections for the property's users and daily movement.

GRADE

Water and elevations considered

Review subgrade, slope and adjacent drainage before forms establish finished levels.

FINISH

A surface chosen for use

Specify the walking texture and joint layout, with decorative choices treated as separate options.

FINISHES AND LAYOUT

Sidewalks Designed Around Your Metro Vancouver Property

Choose the sidewalk route, width and finish around pedestrian access, drainage and adjoining surfaces. Curves, borders, decorative textures and design specific reinforcement can be coordinated where needed.

Concrete sidewalk installation support

Included in our service:

  • • Walkway route and accessibility review

  • • Excavation and compacted subbase preparation

  • • Forms set for width and finished elevation

  • • Drainage slopes away from structures

  • • Trackable concrete from established suppliers

  • • Concrete placement and selected finish

  • • Control joints planned for the walkway

  • • Driveway, stair and entrance transitions

  • • Site access and pedestrian safety coordination

  • • Final walkthrough and care guidance

Additional-cost sidewalk choices

Custom forming for concrete sidewalk layouts

Layout flexibility · Better property access
Concrete sidewalk forming · Curved walkways · Entrance layout

Decorative edging for concrete sidewalks

Finishing detail · Defined walkway borders
Sidewalk edging · Walkway borders · Concrete details

Exposed aggregate concrete sidewalk finish

Popular finish · Textured walking surface
Exposed aggregate sidewalk · Stone texture · Sidewalk finish

Custom shaping, decorative finishes, greater thickness, reinforcement and sealing are considered only where the route, design and written proposal call for them. No add-on is automatic because it appears in this list.

Choose for the route and use

View other available options

Colour choices for a concrete sidewalk

Colour can coordinate a new walkway with steps, patio or driveway concrete. Confirm the finish sample and appearance expectations before adding it to the sidewalk scope. | Additional cost

Stamped pattern for a concrete walkway

A stamped surface can add a pattern to a planned pedestrian route. Review the texture, traction and maintenance with the selected pattern before specifying it. | Additional cost

Concrete sidewalk staining

Staining can change the appearance of a suitable concrete walkway. Surface condition, colour expectations and maintenance should be checked before it is proposed. | Additional cost

Specified sidewalk reinforcement

Rebar may be selected when the sidewalk design and intended loads call for it. It is not assumed for every pedestrian walkway and must be identified in the proposal. | Additional cost

Concrete mix adjustments for sidewalk work

An additive may be considered for documented placement or performance conditions. The concrete mix and any extra cost must be confirmed for this sidewalk project. | Additional cost

Mixed-finish walkway accents

Combining concrete textures can distinguish a border or transition along the sidewalk. The finish pattern and scope should be agreed before forming and placement. | Additional cost

Design-specific sidewalk thickness

A sidewalk used by service vehicles or subject to other loads may need a different design depth. Thickness is determined for the route rather than offered as a blanket upgrade. | Additional cost

Sidewalk sealing choice

Sealing can be considered for the selected walkway finish and maintenance plan. It is not an automatic part of a concrete sidewalk installation. | Additional cost

WHERE THE WALKWAY MEETS OTHER WORK

Coordinate sidewalk connections before the pour

Connections to driveways, patios, stairs, and entrances shape the sidewalk route. For new homes and residential developments, concrete sidewalks can be planned with the driveway, upper- and lower-level concrete steps, and access to a detached garage or shop. During renovations, sidewalk replacement can reconnect an existing entrance to the surrounding property. Confirm finished grades, joints and drainage interfaces before the pour.

Related property work is not automatically included with the sidewalk. Each connection and separate service must be confirmed in the written scope.

  • New-home sidewalk routes

    • New-home sidewalks
    • Entry access
    • Finished grades

    Plan concrete pedestrian access with the new home's entrances, driveway and finished site grades. The home build and sidewalk scope must each be specified in the proposal.

    Explore custom home construction
  • Sidewalk replacement during renovations

    • Sidewalk reno
    • Renovation access
    • New entrance

    Replace a worn or uneven walkway when renovation work changes an entrance or outdoor access route. Coordinate demolition, thresholds and new concrete limits with the renovation plan.

    Explore home renovation services
  • Concrete sidewalks meeting driveways

    • Driveway sidewalks
    • Concrete transitions
    • Pedestrian access

    Coordinate the pedestrian route with the driveway approach so finished elevations, joint locations and surface-water paths meet cleanly. Driveway construction remains a separate scope unless included in the proposal.

    Explore concrete driveway installation
  • Walkways connecting upper and lower concrete stairs

    • Sidewalk stairs
    • Landing grades
    • Level transitions

    Plan sidewalk runs and landings around upper- and lower-level concrete steps so the walking route meets the stair elevations. Stair construction is separately scoped.

    Explore concrete steps and staircases
  • Sidewalk access to detached garages

    • Garage sidewalks
    • Side-door access
    • Garage elevations

    A concrete walkway can link the house, side door and detached garage. Coordinate the route and finished grades with the garage entrance and slab; garage construction is separately scoped.

    Explore detached garage construction
  • Sidewalks connecting to concrete patios

    • Patio walkways
    • Backyard access
    • Concrete transitions

    A backyard sidewalk can meet a patio and guide movement between the house and outdoor areas. Confirm the transition elevation, joint placement and drainage where the separate scopes meet.

    Explore concrete patio installation

DOCUMENTED EXPERIENCE

Concrete sidewalk experience across Metro Vancouver

VALROC builds concrete sidewalks and walkways for residential, strata and commercial properties across Metro Vancouver. Our experience helps coordinate routes, slopes, drainage, accessibility and connections to entrances, driveways, patios and steps. Our crews build pedestrian routes in Langley, Surrey, White Rock, Burnaby, Richmond and New Westminster, working with homeowners, strata councils and businesses where accessibility, inspections and shared access are important.

SCOPE BEFORE PRICE

Plan a concrete sidewalk estimate

Share the proposed route, current surface and access needs. VALROC can then review removal, ground preparation, layout, finish and any separate options before preparing a defined scope.

  • Describe the route

    Show where people need to walk and which entrances or paved areas the sidewalk must meet.

  • Review the property

    Check access, existing concrete, grade changes, drainage and subgrade conditions.

  • Confirm the proposal

    Separate base installation from decorative finishes, design-specific reinforcement and adjacent work.

  • What affects the cost of a concrete sidewalk?

    The route length and width, removal work, site access, ground preparation, grading, forming and chosen finish all affect the scope. Any design-specific thickness, reinforcement or connected property work is priced only when included in the proposal.

    What affects the cost of a concrete sidewalk?

    The route length and width, removal work, site access, ground preparation, grading, forming and chosen finish all affect the scope. Any design-specific thickness, reinforcement or connected property work is priced only when included in the proposal.

    Request Your Free On-site Estimate

    BEFORE INSTALLATION

    Sidewalk Installation Best Practices That Protect Your Property

    Rotary laser-guided grading for precise elevation and slope Strategic sub-grade and compaction to prevent cracking or washout Expert drainage planning to keep water away from home foundations An onsite review should establish route, pedestrian access, sub-grade, finished elevations and drainage connections before a sidewalk scope is priced.

  • 01

    Walk the route

    Identify where the sidewalk starts, ends and connects to doors, parking and other walking surfaces.

  • 02

    Sidewalk needs

    Review existing concrete, subgrade condition, elevation changes and how water moves across the area.

  • 03

    Choose your finish and scope

    Confirm the walking texture, joint layout, removal needs and any separately priced details.

  • 04

    Plan the work

    Discuss temporary pedestrian routes, sequencing and when the new concrete may be used.

  • What the site review confirms

    Grades, surface-water direction, intended loading and any applicable accessibility or municipal requirements are assessed for the actual property. A general page description is not a project design or compliance certification.

    What the site review confirms

    Grades, surface-water direction, intended loading and any applicable accessibility or municipal requirements are assessed for the actual property. A general page description is not a project design or compliance certification.

    PRACTICAL SIDEWALK ANSWERS

    Questions about concrete sidewalk installation

    The connected FAQs cover contractor choice, thickness, weather exposure, timing and care. Project-specific dimensions, accessibility requirements and reopening times still need confirmation for the property.

    What makes VALROC Development Ltd. the best choice for concrete sidewalks?

    Choosing the right contractor for concrete sidewalks comes down to durability, layout accuracy, and how well the sidewalk performs over time.

    • Sidewalks must handle foot traffic, seasonal movement, and occasional service vehicles.
    • Proper forming, finishing, and joint placement affect both safety and longevity.
    • Surface texture plays a role in slip resistance and long-term wear.

    VALROC builds sidewalks with attention to grading, reinforcement, and finish so they remain functional and consistent across the property.

    What makes VALROC Development Ltd. the best choice for concrete sidewalks?

    Choosing the right contractor for concrete sidewalks comes down to durability, layout accuracy, and how well the sidewalk performs over time.

    • Sidewalks must handle foot traffic, seasonal movement, and occasional service vehicles.
    • Proper forming, finishing, and joint placement affect both safety and longevity.
    • Surface texture plays a role in slip resistance and long-term wear.

    VALROC builds sidewalks with attention to grading, reinforcement, and finish so they remain functional and consistent across the property.

    How thick should a concrete sidewalk be?

    Sidewalk thickness depends on how the surface will be used and what loads it may experience.

    • Standard residential sidewalks are typically built for pedestrian traffic.
    • Commercial or public sidewalks often require additional thickness.
    • Areas that cross driveways or service routes need extra reinforcement.

    VALROC determines slab thickness and reinforcement based on site conditions and expected use.

    How thick should a concrete sidewalk be?

    Sidewalk thickness depends on how the surface will be used and what loads it may experience.

    • Standard residential sidewalks are typically built for pedestrian traffic.
    • Commercial or public sidewalks often require additional thickness.
    • Areas that cross driveways or service routes need extra reinforcement.

    VALROC determines slab thickness and reinforcement based on site conditions and expected use.

    How does VALROC ensure sidewalks remain durable in British Columbia’s weather?

    Sidewalk durability in British Columbia depends on how the concrete handles moisture, temperature changes, and ground movement.

    • Freeze-thaw cycles can cause cracking if concrete is not designed for it.
    • Standing water accelerates surface wear and sub-base erosion.
    • Improper joint spacing often leads to uncontrolled cracking.

    VALROC addresses these conditions through concrete selection, drainage planning, and proper joint layout during installation.

    How does VALROC ensure sidewalks remain durable in British Columbia’s weather?

    Sidewalk durability in British Columbia depends on how the concrete handles moisture, temperature changes, and ground movement.

    • Freeze-thaw cycles can cause cracking if concrete is not designed for it.
    • Standing water accelerates surface wear and sub-base erosion.
    • Improper joint spacing often leads to uncontrolled cracking.

    VALROC addresses these conditions through concrete selection, drainage planning, and proper joint layout during installation.

    How long does it take to install a new sidewalk?

    Sidewalk installation timelines vary based on size, layout, and site preparation requirements.

    • Preparation includes excavation, grading, and forming.
    • Concrete placement and finishing are typically completed in a single day.
    • Curing time is required before the sidewalk reaches full strength.

    VALROC sequences the work so sidewalks are installed efficiently while allowing proper curing and finishing.

    How long does it take to install a new sidewalk?

    Sidewalk installation timelines vary based on size, layout, and site preparation requirements.

    • Preparation includes excavation, grading, and forming.
    • Concrete placement and finishing are typically completed in a single day.
    • Curing time is required before the sidewalk reaches full strength.

    VALROC sequences the work so sidewalks are installed efficiently while allowing proper curing and finishing.

    What maintenance is required to keep a concrete sidewalk in good condition?

    Concrete sidewalks require minimal maintenance, but a few basic steps help preserve their condition.

    • Keeping the surface clean prevents staining and organic buildup.
    • Monitoring small cracks early reduces the risk of larger repairs later.
    • Managing nearby drainage helps prevent soil movement beneath the slab.

    VALROC installs sidewalks with long-term performance in mind so maintenance remains straightforward and predictable.

    What maintenance is required to keep a concrete sidewalk in good condition?

    Concrete sidewalks require minimal maintenance, but a few basic steps help preserve their condition.

    • Keeping the surface clean prevents staining and organic buildup.
    • Monitoring small cracks early reduces the risk of larger repairs later.
    • Managing nearby drainage helps prevent soil movement beneath the slab.

    VALROC installs sidewalks with long-term performance in mind so maintenance remains straightforward and predictable.

    METRO VANCOUVER SIDEWALKS

    Concrete sidewalk work across Metro Vancouver

    VALROC installs concrete sidewalks from its Langley construction yard for homes, strata communities, businesses and commercial properties. Route, width, compacted subbase, forming, drainage slope and concrete finish are planned around pedestrian access, entrances and connections to driveways or stairs.

    Walkways in Surrey and White Rock may connect changing grades and outdoor spaces, while Burnaby properties can require careful work in tighter side yards or entrance areas. In Delta, longer routes may connect parking, service areas and detached buildings. Accessibility and municipal context are reviewed for the proposed path.