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

SPACE BUILT FOR THE WORK

Custom Shops Built for Performance and Precision Across Metro Vancouver

High-quality, custom-built workshops tailored to your needs, ideal for hobbies, mechanics, business, or specialized equipment. A custom shop should fit the work it will hold, the equipment it must support and the property it occupies. VALROC coordinates the site, slab, structure and selected services around the approved use.

Zoning, loads, utilities and finish choices are confirmed before the build scope is finalized.

Valroc Development Ltd. builds a large custom shop in Langley BC
WORKFLOW

Lay out the shop for real tasks

Plan bays, circulation and storage around vehicles, tools or production.

LOADS

Specify the supporting slab

Review equipment weight, lift needs and service routes before concrete work.

ENVELOPE

Protect the working space

Coordinate doors, roofing, insulation and ventilation with intended use.

FROM PLAN TO COMPLETION

How a custom shop is built

The linked sequence covers discovery, site preparation, foundations, framing, weather protection and selected finishing features. The exact electrical or mechanical scope depends on the approved plans.

  1. Rebar and formwork setup for concrete slab foundation

    Step 1

    Custom Shop Planning

    Initial consultation and planning phase for custom shop construction projects, including use-case discovery, permitting, scope development, contracts, and complete client onboarding.

    • Shop use
    • Workflow planning
    • Bay layout
  2. Site clearing with full-size excavator

    Step 2

    Custom Shop Site Prep

    Mobilization and site prep for custom shop construction, including clearing, demolition, layout prep, utility trenching, and excavation for structural foundation builds.

    • Shop site prep
    • Equipment access
    • Mobilization
  3. Beginning of installing rebar for custom garage slab

    Step 3

    Custom Shop Foundations

    Foundation phase for custom shop construction, including site layout, utility trenching, engineered fill, heavy-duty formwork, rebar, vapour barriers, concrete pouring, and slab finishing.

    • Shop foundation
    • Concrete slab
    • Load planning
  4. Valroc crew lifting large custom garage wall into place

    Step 4

    Custom Shop Framing

    Structural framing phase for custom shop construction, including wall and roof framing, engineered connections, window and door install, and full building enclosure to lock-up stage.

    • Shop framing
    • Door openings
    • Building lockup
  5. Finished exterior siding on custom-built shop

    Step 5

    Custom Shop Exterior Finishes

    Exterior finishing phase for custom shops, including siding, roofing systems, flashing, ventilation, and moisture protection, tailored for long-term durability and high-use applications.

    • Shop envelope
    • Roof protection
    • Weatherproofing
  6. Installing custom railings for second story garage

    Step 6

    Custom Shop Finishing

    Finishing phase for custom shops, including utility rooms, wash stations, trench drains, concrete driveways, structural upgrades for hoists or second floors, and integration with mechanical systems.

    • Shop utilities
    • Equipment needs
    • Site integration

BUILT AROUND THE USE

Plan the custom shop around its purpose

Custom-built shops designed to support hobbies, mechanical work, business use, or specialized equipment.

End-to-end construction including foundations, utilities, structural framing, and interior build-outs.

Durable, functional structures built for long-term use, efficient workflows, and property compatibility.

Whether you’re building your dream hobby workshop or need a functional space for business or specialized equipment, VALROC Development Ltd. delivers fully customized shop builds designed to match your exact needs. These structures can serve personal, mechanical, or light industrial purposes all backed by our end-to-end construction expertise.

Built Around Your Goals

Each shop is designed based on your goals, usage type, and property layout. Our team handles every element, from excavation and permitting to framing, finishing, and full-service utility connections.

Custom shop construction can support hobby work, vehicle service or business operations when the property and zoning permit that use. Building dimensions, clearances, slab loads and utilities should follow the intended workflow.

BAYS

Set working clearances

Size doors, ceiling height and circulation for the intended equipment.

SLAB

Plan equipment loads

Discuss lifts, heavy tools and floor performance early.

UTILITIES

Coordinate service capacity

Locate power, lighting, ventilation and plumbing in the design.

ACCESS

Connect the shop to the site

Plan vehicle approaches, drainage and material movement.

SELECT THE DETAILS

Choices that shape the custom shop

Plan the shop around equipment, vehicle access, working space and future use. Slab loads, bay layout, power, ventilation, plumbing and interior finishes are coordinated with the approved design.

Custom shop construction support

Included in our service:

  • • Shop layout and intended use planning

  • • Permit and engineered plan coordination

  • • Site preparation, footings and foundations

  • • Structural framing and building envelope work

  • • Slab, access and drainage coordination

  • • Door, window and utility planning

  • • Specialized equipment and organized site service

  • • Material ordering from established suppliers

  • • Municipal inspection scheduling

  • • Construction walkthrough and documented handoff

Door sizes, bay layout, insulation, power capacity, ventilation, plumbing and interior finishes are custom decisions. Their availability and price depend on approved use, design and written selections.

Keep selections connected to the plan

PLAN THE CONNECTIONS

Connect the custom shop to the wider property

Utility trenching for power, gas, and plumbing, fully integrated into site plans Wide garage door access with concrete apron tie-ins and drive paths Drainage solutions to protect your slab and surrounding areas Shop construction can meet a concrete apron, driveway, drainage system or utility trench. Those property connections should be designed together but remain distinct contract items.

Vehicle approaches, utility capacity upgrades, gas service, plumbing and specialized equipment installations are not automatic parts of a custom shop build.

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

    Site preparation for custom shop construction

    • Custom shop site
    • Building pad
    • Equipment access

    A custom shop needs a prepared building area with practical equipment access, material storage and finished grades. Early preparation supports the foundation, services and large door approaches that follow.

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

    Excavation and grading for custom shops

    • Custom shop excavation
    • Site grading
    • Material hauling

    Shop construction may involve building excavation, utility routes, drainage shaping and significant aggregate movement. Coordinated excavation and trucking help prepare the site for structural work and vehicle access.

    Explore excavation and machine services
  • Foundations and footings for custom shop buildings

    • Shop foundation
    • Structural footings
    • Building loads

    Custom shops often carry concentrated structural loads and require carefully planned door, wall and equipment locations. Foundation and footing construction should follow the building design and actual property conditions.

    Explore foundations and footings
  • Concrete garage slabs for custom shop floors

    • Custom shop slab
    • Concrete work floor
    • Equipment loads

    A concrete slab creates the working floor for vehicles, tools and equipment inside a custom shop. Slab thickness, reinforcement, drainage and finish can be coordinated around how the building will be used.

    Explore concrete garage slabs
  • Asphalt parking and loading areas for custom shops

    • Shop parking lot
    • Loading access
    • Commercial paving

    Commercial and light industrial shops often need durable exterior space for staff parking, deliveries and vehicle movement. Asphalt layout and grades can be planned around doors, loading areas and drainage.

    Explore asphalt parking lot installation
  • Aaron team member installing a trench drain in front of a garage diverting water that has been damaging the concrete and undermining the foundation

    Trench drains for custom shop entrances

    • Shop trench drain
    • Doorway drainage
    • Floor protection

    Wide shop doors can receive runoff, snowmelt and wash water from exterior paved areas. A trench drain across the entrance can help protect the interior floor and support easier water management.

    Explore trench drain installation

DOCUMENTED EXPERIENCE

Custom shop experience from the ground up

VALROC brings experience in excavation, foundations, concrete, drainage and complete construction to custom shop projects across Metro Vancouver. We review how the building will be used so the structure, access and supporting site work can be planned together. With our construction yard in Langley, we are well positioned for shop projects in Aldergrove, Surrey, Maple Ridge and the Fraser Valley side of Metro Vancouver, including coordination with engineers, architects and local inspectors.

DEFINE THE BUILD SCOPE

Discuss a custom shop proposal

Share plans, intended use and property details with VALROC. An onsite review helps establish the scope and selections before a custom shop proposal is prepared.

  • Share the project

    Explain your intended use, available plans and goals.

  • Review the property

    Confirm property access, zoning, intended work, vehicle dimensions, equipment loads, utilities and drainage before recommending a shop layout.

  • Confirm the proposal

    Compare the selected stages, materials, allowances and boundaries in writing.

  • What affects a custom shop estimate?

    Site preparation, shop dimensions, foundation loads, door openings, envelope, power, ventilation, finishes and access affect cost. A property review is needed before providing a specific price.

    What affects a custom shop estimate?

    Site preparation, shop dimensions, foundation loads, door openings, envelope, power, ventilation, finishes and access affect cost. A property review is needed before providing a specific price.

    Request Your Free On-site Estimate

    CHECK THE PROPERTY AND PLANS

    Assess the site before a custom shop build

    Confirm property access, zoning, intended work, vehicle dimensions, equipment loads, utilities and drainage before recommending a shop layout.

  • 01

    Confirm the use

    Define what the completed building needs to support.

  • 02

    Review the site

    Confirm property access, zoning, intended work, vehicle dimensions, equipment loads, utilities and drainage before recommending a shop layout.

  • 03

    Resolve approvals

    Review zoning, drawings and permit responsibilities for this property.

  • 04

    Write the scope

    Record the structure, systems, selections and separately scoped work.

  • What needs confirmation

    A lift, machinery or commercial use may need structural or code requirements beyond a general workshop. The approved design must resolve these before installation.

    What needs confirmation

    A lift, machinery or commercial use may need structural or code requirements beyond a general workshop. The approved design must resolve these before installation.

    ANSWERS REQUIRE PROJECT CONTEXT

    Questions about custom shop construction

    The linked questions address shop types, customization, permits, delivery and timing. Any statement about faster completion must be supported by the actual project schedule.

    What are the benefits of building a custom shop instead of using a pre-built structure?

    A custom-built shop gives you control over how the space functions instead of forcing your needs into a fixed design.

    • Layouts designed around workflow rather than generic dimensions.
    • Structural capacity matched to equipment, vehicles, or production use.
    • Better insulation and energy performance for long-term comfort.
    • Materials and finishes selected for durability instead of minimum cost.
    • Flexibility to adapt the space as needs change over time.

    This approach usually results in a more efficient and longer-lasting building.

    What are the benefits of building a custom shop instead of using a pre-built structure?

    A custom-built shop gives you control over how the space functions instead of forcing your needs into a fixed design.

    • Layouts designed around workflow rather than generic dimensions.
    • Structural capacity matched to equipment, vehicles, or production use.
    • Better insulation and energy performance for long-term comfort.
    • Materials and finishes selected for durability instead of minimum cost.
    • Flexibility to adapt the space as needs change over time.

    This approach usually results in a more efficient and longer-lasting building.

    What types of custom shops does VALROC build?

    Custom shops vary widely depending on how the space will be used and what it needs to support.

    • Automotive and mechanical shops designed for lifts and heavy tools.
    • Woodworking and carpentry shops with ventilation and dust control.
    • Fabrication and welding shops built for heat, load, and safety.
    • Commercial and industrial workshops scaled for production or storage.
    • Creative studios and mixed-use spaces requiring flexible layouts.

    Each shop is designed around function first, with finishes selected to match.

    What types of custom shops does VALROC build?

    Custom shops vary widely depending on how the space will be used and what it needs to support.

    • Automotive and mechanical shops designed for lifts and heavy tools.
    • Woodworking and carpentry shops with ventilation and dust control.
    • Fabrication and welding shops built for heat, load, and safety.
    • Commercial and industrial workshops scaled for production or storage.
    • Creative studios and mixed-use spaces requiring flexible layouts.

    Each shop is designed around function first, with finishes selected to match.

    What customization options are available for my shop?

    A custom shop is planned around how you intend to work in the space, not a fixed layout or pre-set package.

    • Building size and bay layout based on vehicles, equipment, and workflow.
    • Concrete slab thickness and reinforcement matched to lifts, machinery, or storage loads.
    • Electrical and lighting designed for real tool use, not minimum code only.
    • Insulation, heating, and ventilation suited to year-round use.
    • Storage areas, workbenches, and circulation planned to keep the space efficient.
    • Floor finishes selected for durability, traction, and maintenance.

    The result is a shop that supports how you actually work, without compromise.

    What customization options are available for my shop?

    A custom shop is planned around how you intend to work in the space, not a fixed layout or pre-set package.

    • Building size and bay layout based on vehicles, equipment, and workflow.
    • Concrete slab thickness and reinforcement matched to lifts, machinery, or storage loads.
    • Electrical and lighting designed for real tool use, not minimum code only.
    • Insulation, heating, and ventilation suited to year-round use.
    • Storage areas, workbenches, and circulation planned to keep the space efficient.
    • Floor finishes selected for durability, traction, and maintenance.

    The result is a shop that supports how you actually work, without compromise.

    What permits are required to build a custom shop, and does VALROC handle them?

    Permit requirements depend on zoning, size, intended use, and included services.

    • Zoning and land-use review to confirm what is allowed.
    • Building permits for structure, foundation, and slab work.
    • Electrical, plumbing, or mechanical permits if required.
    • Engineering review where loads or spans exceed standard design.

    VALROC manages the permitting process so construction can proceed without delays.

    What permits are required to build a custom shop, and does VALROC handle them?

    Permit requirements depend on zoning, size, intended use, and included services.

    • Zoning and land-use review to confirm what is allowed.
    • Building permits for structure, foundation, and slab work.
    • Electrical, plumbing, or mechanical permits if required.
    • Engineering review where loads or spans exceed standard design.

    VALROC manages the permitting process so construction can proceed without delays.

    Why should I choose VALROC Development Ltd. to build my custom shop?

    Building a shop involves more than framing a structure. It requires coordination, sequencing, and experience with heavy-use buildings.

    • Site preparation, foundations, and slabs handled in-house.
    • Experience building shops for residential, commercial, and industrial use.
    • Clear planning around access, loads, and future expansion.
    • One coordinated team managing permits, construction, and finishes.
    • Equipment and crew sized for efficient scheduling and fewer delays.

    The focus is on building something that works long-term, not just passing inspection.

    Why should I choose VALROC Development Ltd. to build my custom shop?

    Building a shop involves more than framing a structure. It requires coordination, sequencing, and experience with heavy-use buildings.

    • Site preparation, foundations, and slabs handled in-house.
    • Experience building shops for residential, commercial, and industrial use.
    • Clear planning around access, loads, and future expansion.
    • One coordinated team managing permits, construction, and finishes.
    • Equipment and crew sized for efficient scheduling and fewer delays.

    The focus is on building something that works long-term, not just passing inspection.

    How does VALROC complete custom shop projects faster than other builders?

    Project timelines are usually affected by coordination gaps, subcontractor delays, and site readiness.

    • In-house excavation, concrete, and site preparation.
    • Equipment sized for foundation and slab work without outsourcing.
    • Pre-planned sequencing that avoids idle time between trades.
    • Clear scopes and scheduling before construction starts.
    • Fewer handoffs between crews during critical phases.

    This keeps work moving without rushing the parts that matter.

    How does VALROC complete custom shop projects faster than other builders?

    Project timelines are usually affected by coordination gaps, subcontractor delays, and site readiness.

    • In-house excavation, concrete, and site preparation.
    • Equipment sized for foundation and slab work without outsourcing.
    • Pre-planned sequencing that avoids idle time between trades.
    • Clear scopes and scheduling before construction starts.
    • Fewer handoffs between crews during critical phases.

    This keeps work moving without rushing the parts that matter.

    METRO VANCOUVER BUILDING

    Custom Shop projects across Metro Vancouver

    VALROC supports custom shop construction from its Langley yard, coordinating excavation, foundations, structural work, slabs, equipment access and material deliveries. Shops in Langley and Surrey may be designed for vehicle storage, trades, property maintenance or light industrial use, with the building systems planned around the intended work.

    Projects in Delta and Burnaby require their own approach to access, drainage, service capacity and municipal review. VALROC coordinates approved plans, established suppliers, specialized equipment and inspection stages so the shop and surrounding property function together.