/* update variables when header is on dark background*/
.on-dark-bg {
   --header-bg: var(--current-header-bg);
   --chevron-clr: white;
   --menu-item-clr: white;
   --menu-item-hover-bg: #172235;
   --menu-item-hover-clr: #bc92e6;
   --menu-toggle-clr: var(--menu-item-clr);
   --dropdown-content-border: solid 1px rgb(220 220 220 / 20%);
   --mobile-menu-bg: var(--header-bg);
 }

 .on-light-bg {
   --menu-item-clr: black;
   /* update variables when header is on light background*/
 }


 /* update variable when on dark or light background */
 .on-dark-bg,
 .on-light-bg {
   --overlay-header-bg-active: var(--current-header-bg);
   --dropdown-content-bg: var(--current-header-bg);
 }

 .on-video-section {
   /* update variables when header is on video section*/
   --menu-item-clr: white;
   --chevron-clr: white;
   --menu-item-hover-bg: rgb(0 0 0 / 30%);
   --menu-item-hover-clr: #bc92e6;
   --dropdown-content-bg: rgb(0 0 0 / 70%);
   --overlay-header-bg: rgb(0 0 0 / 25%);
   --overlay-header-bg-active: var(--dropdown-content-bg);
   --dropdown-content-border: solid 1px rgb(220 220 220 / 20%);
   --current-header-bg: rgb(0 0 0 / 14%) !important;
   --header-bg: rgb(0 0 0 / 70%);
   --menu-toggle-clr: white;
   --mobile-menu-bg: rgb(0 0 0 / 95%);
   --menu-cta-border: var(--dropdown-content-border)
 }


 .on-hero-section {
   /* update variables when header is on hero section*/
 }

 /* header bg blure when on video section */
 html:not(.dwc-mobile) .dwc-nest-header.on-video-section {
   backdrop-filter: blur(var(--overlay-header-blur));
 }

 /* overlay header border when on video section or dark background*/
 .dwc-nest-header:is(.on-dark-bg, .on-video-section)[data-overlay-header="true"] {
   border: 1px solid rgba(255, 255, 255, 0.2);
 }

 /* header bottom border when on dark background or video section*/
 .dwc-nest-header:is(.on-dark-bg, .on-video-section) {
   border-bottom: 1px solid rgba(255, 255, 255, 0.2);
 }


 /* logo color when on dark background*/
 .on-dark-bg .dwc-nest-menu__logo path {
   fill: white;
 }

 /* logo color when on light background*/
 .on-dark-bg .dwc-nest-menu__logo path {
   /*define svg fill when logo is on light background */
 }

 /* logo color when on video background*/
 .on-video-section .dwc-nest-menu__logo path {
   fill: white;
 }

/*custom */

.on-dark-bg .mega-menu-magic__menu-icon-large{
   background-color: var(--current-header-bg);
    fill: #bc92e6;
    color: #bc92e6;
}

.on-video-section .mega-menu-magic__menu-icon-large{
   background-color: var(--current-header-bg);
    fill: #bc92e6;
    color: #bc92e6;
}

.on-video-section .mega-menu-magic__dropdown-title,
.on-dark-bg .mega-menu-magic__dropdown-title{
    color: rgb(210 210 210);   
}
// Constants
const BREAKPOINT_DESKTOP = 0;
const DEBOUNCE_DELAY = 50;

// Configuration object for all header-related selectors
const HEADER_CONFIG = {
  // Main header element
  headerElement: '.dwc-nest-header',
  // Wrapper element selectors (can be classes, IDs, or data attributes)
  wrapperSelectors: [
    // '.dwc-nest-header__container'
  ],
  // Elements to monitor for header styling (can include any CSS selector)
  // Default monitors sections, but you can add footer, divs, or any element
  monitoredElements: 'section, [data-header-zone]',
  // Store original header background color
  originalHeaderBgColor: null
};

// Unified section type configuration
// Add new data attributes here - they will be automatically mapped to header classes
const SECTION_TYPES = {
  'data-hero': 'on-hero-section',
  'data-video': 'on-video-section',
  'data-custom': 'on-custom-section',
  'data-sticky': 'on-media-section'
  // Add new: 'data-feature': 'on-feature-section'
};

// Configuration for excluded sections
const EXCLUSION_CONFIG = {
  // Data attribute that identifies sections to exclude from header styling
  sectionAttribute: 'data-exclude-header'
};

// Text color classes
const TEXT_CLASSES = {
  light: 'on-dark-bg',
  dark: 'on-light-bg'
};

// Generate classes to remove dynamically from SECTION_TYPES and text classes
const ALL_CLASSES_TO_REMOVE = [
  // Add all header classes from section types
  ...Object.values(SECTION_TYPES),
  // Add text color classes
  TEXT_CLASSES.light,
  TEXT_CLASSES.dark
];

// Performance optimization: Cache DOM elements and computed values
const CACHE = {
  headerElement: null,
  wrapperElement: null,
  sections: [],
  sectionsData: new Map(),
  colorCache: new Map(),
  tempColorElement: null,
  lastKnownSection: null,
  isUpdating: false,
  pendingColorUpdate: false
};

// Initialize cache
function initializeCache() {
  // Cache header elements
  CACHE.headerElement = document.querySelector(HEADER_CONFIG.headerElement);
  
  // Try each wrapper selector until one is found
  for (const selector of HEADER_CONFIG.wrapperSelectors) {
    CACHE.wrapperElement = document.querySelector(selector);
    if (CACHE.wrapperElement) break;
  }
  
  // Cache sections and their positions
  CACHE.sections = Array.from(document.querySelectorAll(HEADER_CONFIG.monitoredElements));
  
  // Create reusable element for color calculations
  CACHE.tempColorElement = document.createElement('div');
  CACHE.tempColorElement.style.position = 'absolute';
  CACHE.tempColorElement.style.visibility = 'hidden';
  CACHE.tempColorElement.style.pointerEvents = 'none';
  document.body.appendChild(CACHE.tempColorElement);
  
  // Cache section metadata
  updateSectionsCache();
}

// Update sections cache (call when DOM changes)
function updateSectionsCache() {
  CACHE.sections = Array.from(document.querySelectorAll(HEADER_CONFIG.monitoredElements));
  CACHE.sectionsData.clear();
  
  CACHE.sections.forEach((section, index) => {
    const sectionData = {
      index,
      isExcluded: section.hasAttribute(EXCLUSION_CONFIG.sectionAttribute)
    };
    
    // Dynamically check for all section types defined in SECTION_TYPES
    Object.keys(SECTION_TYPES).forEach(attribute => {
      sectionData[attribute] = section.hasAttribute(attribute);
    });
    
    CACHE.sectionsData.set(section, sectionData);
  });
}

// Function to remove all section classes from :root only
function removeAllSectionClasses() {
  const rootElement = document.documentElement;
  
  // Remove classes from :root only
  rootElement.classList.remove(...ALL_CLASSES_TO_REMOVE);
}

// Function to update the CSS variable on :root
function updateRootBackgroundVariable(color) {
  document.documentElement.style.setProperty('--current-header-bg', color);
}

// Function to apply classes to :root only
function applyClassesToRoot(headerClass, textClass) {
  const rootElement = document.documentElement;
  
  // Apply header class to :root only
  if (headerClass) {
    rootElement.classList.add(headerClass);
  }
  
  // Apply text class to :root only
  if (textClass) {
    rootElement.classList.add(textClass);
  }
}

// Optimized color conversion using cached temp element
function getRGBValues(color) {
  const cacheKey = color;
  if (CACHE.colorCache.has(cacheKey)) {
    return CACHE.colorCache.get(cacheKey);
  }
  
  CACHE.tempColorElement.style.color = color;
  const computedColor = window.getComputedStyle(CACHE.tempColorElement).color;
  
  // Extract RGB values
  const match = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
  const result = match ? {
    r: parseInt(match[1]),
    g: parseInt(match[2]),
    b: parseInt(match[3])
  } : { r: 255, g: 255, b: 255 };
  
  // Cache the result
  CACHE.colorCache.set(cacheKey, result);
  return result;
}

// Function to check if a background color is transparent or empty
function isBackgroundTransparent(color) {
  if (!color) return true;
  
  const transparentValues = [
    'transparent',
    'rgba(0, 0, 0, 0)',
    'rgba(0,0,0,0)',
    'initial',
    'inherit',
    ''
  ];
  
  return transparentValues.includes(color.toLowerCase().replace(/\s/g, ''));
}

// Function to determine if a color is dark or light
function isColorDark(color) {
  if (color === 'transparent' || color === 'rgba(0, 0, 0, 0)') {
    return false;
  }
  
  const rgb = getRGBValues(color);
  const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
  return luminance < 0.5;
}

// Optimized section detection using cached data
function getCurrentSection() {
  if (!CACHE.headerElement || CACHE.sections.length === 0) return null;
  
  const headerHeight = CACHE.headerElement.offsetHeight;
  
  // Quick check if we're still in the same section
  if (CACHE.lastKnownSection) {
    const rect = CACHE.lastKnownSection.getBoundingClientRect();
    if (rect.top <= headerHeight && rect.bottom > headerHeight) {
      return CACHE.lastKnownSection;
    }
  }
  
  // Binary search would be ideal here, but simple loop is sufficient for most cases
  for (const section of CACHE.sections) {
    const rect = section.getBoundingClientRect();
    if (rect.top <= headerHeight && rect.bottom > headerHeight) {
      CACHE.lastKnownSection = section;
      return section;
    }
  }
  
  const firstSection = CACHE.sections[0] || null;
  CACHE.lastKnownSection = firstSection;
  return firstSection;
}

// Function to get computed background color with caching
function getComputedBackgroundColor(element) {
  const cacheKey = element;
  if (CACHE.colorCache.has(cacheKey)) {
    return CACHE.colorCache.get(cacheKey);
  }
  
  const bgColor = window.getComputedStyle(element).backgroundColor;
  CACHE.colorCache.set(cacheKey, bgColor);
  return bgColor;
}

// Function to initialize original header background color
function initializeOriginalHeaderBgColor() {
  if (CACHE.headerElement) {
    HEADER_CONFIG.originalHeaderBgColor = window.getComputedStyle(CACHE.headerElement).backgroundColor;
  }
}

// Function to determine header style configuration based on section
function determineHeaderConfig(section) {
  if (!section) return null;
  
  const sectionData = CACHE.sectionsData.get(section);
  if (!sectionData) return null;
  
  // If section is excluded, return null to skip styling
  if (sectionData.isExcluded) {
    return null;
  }
  
  // Dynamically check for any section type defined in SECTION_TYPES
  for (const [attribute, headerClass] of Object.entries(SECTION_TYPES)) {
    if (sectionData[attribute]) {
      return {
        backgroundColor: null,
        headerClass: headerClass,
        needsWhiteText: null,
        isSpecialSection: true
      };
    }
  }
  
  // Get the actual background color of the section
  const sectionBgColor = getComputedBackgroundColor(section);
  
  if (isBackgroundTransparent(sectionBgColor)) {
    return {
      backgroundColor: HEADER_CONFIG.originalHeaderBgColor || 'rgb(255, 255, 255)',
      headerClass: null,
      needsWhiteText: isColorDark(HEADER_CONFIG.originalHeaderBgColor || 'rgb(255, 255, 255)'),
      isSpecialSection: false
    };
  }
  
  const needsWhiteText = isColorDark(sectionBgColor);
  
  return {
    backgroundColor: sectionBgColor,
    headerClass: null,
    needsWhiteText: needsWhiteText,
    isSpecialSection: false
  };
}

// Function to apply styles (background color to header, classes to :root only)
function applyHeaderStyles(config) {
  if (!CACHE.headerElement || !config) return;
  
  const elementsToStyle = [CACHE.headerElement, CACHE.wrapperElement].filter(Boolean);
  
  // Use requestAnimationFrame for smooth visual updates
  requestAnimationFrame(() => {
    // First, remove all section classes and text classes from :root only
    removeAllSectionClasses();
    
    // Update the root CSS variable with background color
    if (config.backgroundColor !== null) {
      const appliedBgColor = config.backgroundColor || '';
      updateRootBackgroundVariable(appliedBgColor);
    } else {
      updateRootBackgroundVariable('');
    }
    
    // Determine text class to apply
    const textClass = config.needsWhiteText !== null 
      ? (config.needsWhiteText ? TEXT_CLASSES.light : TEXT_CLASSES.dark)
      : null;
    
    // Apply classes to :root only
    applyClassesToRoot(config.headerClass, textClass);
    
    // Handle background color on header elements only
    elementsToStyle.forEach(element => {
      if (config.backgroundColor !== null) {
        const appliedBgColor = config.backgroundColor || '';
        element.style.backgroundColor = appliedBgColor;
      } else {
        element.style.backgroundColor = '';
      }
    });
    
    // For special sections, allow CSS to apply first, then get computed background color
    if (config.isSpecialSection && config.headerClass) {
      // Use setTimeout(0) to ensure CSS has been applied, but batch multiple calls
      if (!CACHE.pendingColorUpdate) {
        CACHE.pendingColorUpdate = true;
        setTimeout(() => {
          // Process all elements that need color updates in this batch
          elementsToStyle.forEach(el => {
            // Check if element has any of the section classes (though they're not applied anymore)
            const hasSectionClass = Object.values(SECTION_TYPES).some(className => 
              el.classList.contains(className)
            );
            
            if (hasSectionClass) {
              const computedBgColor = getComputedBackgroundColor(el);
              updateRootBackgroundVariable(computedBgColor);
            }
          });
          CACHE.pendingColorUpdate = false;
        }, 50);
      }
    }
    
    CACHE.isUpdating = false;
  });
}

// Throttled update function using requestAnimationFrame
function updateHeaderStyles() {
  // Prevent multiple updates in the same frame
  if (CACHE.isUpdating) return;
  
  // Apply only on screens larger than the breakpoint
  if (window.innerWidth <= BREAKPOINT_DESKTOP) {
    return;
  }
  
  CACHE.isUpdating = true;
  
  const currentSection = getCurrentSection();
  if (!currentSection) {
    CACHE.isUpdating = false;
    return;
  }
  
  const headerConfig = determineHeaderConfig(currentSection);
  if (!headerConfig) {
    CACHE.isUpdating = false;
    return;
  }
  
  applyHeaderStyles(headerConfig);
}

// Debounce function for resize events (less frequent)
function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

// RAF-based throttle for scroll events
let rafId = null;
function throttleWithRAF(func) {
  return function(...args) {
    if (rafId) return;
    
    rafId = requestAnimationFrame(() => {
      func.apply(this, args);
      rafId = null;
    });
  };
}

// Initialize everything
function initialize() {
  initializeCache();
  initializeOriginalHeaderBgColor();
  updateHeaderStyles();
}

// Cleanup function
function cleanup() {
  if (CACHE.tempColorElement && CACHE.tempColorElement.parentNode) {
    CACHE.tempColorElement.parentNode.removeChild(CACHE.tempColorElement);
  }
  if (rafId) {
    cancelAnimationFrame(rafId);
  }
}

// Initialize on page load
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initialize);
} else {
  initialize();
}

// Create optimized event handlers
const throttledUpdateHeaderStyles = throttleWithRAF(updateHeaderStyles);
const debouncedUpdateHeaderStyles = debounce(() => {
  updateSectionsCache(); // Refresh cache on resize
  updateHeaderStyles();
}, DEBOUNCE_DELAY);

// Add event listeners with passive option for better performance
window.addEventListener('scroll', throttledUpdateHeaderStyles, { passive: true });
window.addEventListener('resize', debouncedUpdateHeaderStyles, { passive: true });

// Cleanup on page unload
window.addEventListener('beforeunload', cleanup);

Case studies

Purpose-Built Fitness for Public Safety Professionals.

Agency units prioritize similar training styles across the board. The focus is on improving power, strength, agility, and speed—while also supporting cardiovascular health, which remains the leading cause of on‑duty fatalities among public‑safety personnel. Functional movement and practice routines also remain crucial for field readiness.

Building A Stronger Foundation

In 2022, Advantage interviewed Russel Vidler, a New York State Fire Inspector and Lead Physical Training Instructor for the NYS Fire Academy Recruit Firefighter Program.

During this eye-opening interview, Vidler emphasized how fitness is transforming firefighter performance—boosting cardiovascular health, endurance, sleep, strength, and confidence on and off the job. 

“We’re trying to expand the fire department mindset through healthier habits.” –  Russel Vidler, New York State Fire Inspector & Lead Physical Training Instructor for the NYS Fire Academy Recruit Firefighter Program

Gym set up

His perspective on the connection between training, equipment, and readiness still holds true today and extends far beyond firehouses. From police precincts to military installations, all public agencies are prioritizing fitness as a means to protect their teams, be their best on the job, and strengthen their communities.

What Statistics Say

  • As of 2024, overexertion or strain injuries continue to represent the leading cause of firefighter deaths with 40 fatal injuries (65 percent) in 2024. – National Fire Protection Agency (NFPA)
  • “Officers who engaged in regular fitness training were less likely to suffer OSHA‑reportable or severe injuries.” – IACP, Reducing Officer Injuries Final Report. 

The Right Tools

Agency units prioritize similar training styles across the board. The focus is on improving power, strength, agility, and speed—while also supporting cardiovascular health, which remains the leading cause of on‑duty fatalities among public‑safety personnel. Functional movement and practice routines also remain crucial for field readiness.

“In a functional fitness program, it’s all about taking the movements that you use on the job and then getting the equipment to incorporate those movements into your program.” – Russel Vidler, New York State Fire Inspector & Lead Physical Training Instructor for the NYS Fire Academy Recruit Firefighter Program

Gym set up

To support these goals, agency training spaces seek out equipment in a few key areas.

  1. Functional Training Tools: Functional frames, sleds, accessories (corebags, bulgarian bags, kettlebells) – simulating real-world tasks and movement.
  2. Cardio: Treadmills, bikes, stair climbers, rowers – building endurance and cardiovascular health.
  3. Strength: Racks, plate-loaded and selectorized machines, dumbbells, – supporting overall conditioning.

Mission Support

Public agencies face many of the same challenges as any organization planning a training facility—tight budgets, limited space, or uncertainty about what mix of equipment will best serve their people.

Every agency’s path is different—whether it’s creatively sourcing funding, finding the right space, or determining the best balance of equipment. Advantage is here to support each unique journey. 

Gym set up

Building Readiness Through Response

When this Hudson Valley, NY fire department rebuilt and relocated, they made continued training the cornerstone of preparation—a place to build strength, endurance, and resilience, all critical for operational success. The gym was also designed as a hub for firehouse culture. Vibrant colors and a thoughtful layout create a welcoming environment for every firefighter and supporting staff member. With this new firehouse came a new tradition and a fresh start. From the outset, the department made it a priority to bake mission success into the project—carefully budgeting and planning for a training area that would support their goals, their work and in turn, their community.

Unified By Mission

When first responders and service members across fire, police, and military sectors invest in purpose-built training spaces, the impact extends far beyond upgraded equipment—it reshapes culture, readiness, and pride.

In the Hudson Valley, a rebuilt firehouse placed ongoing training at the center of its mission, creating a vibrant, community-focused gym that strengthens both operational performance and firehouse culture.

Gym set up

At the Altoona Police Department, leadership recognized the value of conditioning in reducing injuries, improving decision-making, and elevating job performance. With Lt. Vasil championing the initiative, the department transformed unused space into a dedicated training room that now fuels camaraderie, wellness, and a renewed sense of identity.

Gym set up

Similarly, for a National Guard unit supported by full-time guards and rotating soldiers, SFC Kramer spearheaded efforts to secure funding and design a facility that meets rigorous physical standards and fosters long-term development. Across each department, thoughtful customizations—from branded equipment to intentional layouts—build unity, boost morale, and reinforce the shared mission: keeping their teams strong, capable, and ready to serve their communities.

Ready to start your next project? Reach out to the Advantage team today.

Our services

We are ready to support your facility in every phase.

Partner Brands

Explore our collection of partner brands.

All Partner Brands
Case Studies

Examples of our work.

All Case Studies