import { observeCurrencyFormatting, applyTypographyStyles } from './utils/formatting.js';
import { applyPlaceholderScenario } from './utils/placeholder-scenarios.js';
import { applyThemedPanels } from './utils/theme.js';
import { __, applyInputLabelTruncation, TooltipPortal } from '@vareoncalc/calculator-base';

function mountWithTheme(module, el) {
  if (!module || typeof module.mount !== 'function') {
    return;
  }
  module.mount(el);
  applyInputLabelTruncation(el);
  applyPlaceholderScenario(el, el.dataset.vareoncalcType || '');
  applyThemedPanels(el);
  applyTypographyStyles(el.closest('.vareoncalc-root') || el);
}

function normalizeAutoCalcDelay(rawDelay) {
  const delay = parseInt(rawDelay, 10);
  if (Number.isNaN(delay)) {
    return 400;
  }

  // Back-compat: legacy 300ms becomes 400ms (Lite uses 400ms).
  if (300 === delay) {
    return 400;
  }

  if (0 === delay || 400 === delay || 800 === delay) {
    return delay;
  }

  return 400;
}

(async function () {
  const CFG = window.VAREONCALC_CFG || { proEnabled: false };
  CFG.formatting = CFG.formatting || {};
  CFG.measurement = CFG.measurement || {};
  if (CFG.pluginUrl) {
    try {
      CFG.pluginUrl = new URL(String(CFG.pluginUrl), window.location.origin).toString();
    } catch {
    }
  }
  window.VAREONCALC_CFG = CFG;

  TooltipPortal.init();
  window.vareoncalcTooltipPortal = TooltipPortal;

  const assetVersion = CFG.assetVersion || CFG.version || '1';
  const isLocalhost = typeof window !== 'undefined'
    && /^(localhost|127\.0\.0\.1)$/i.test(window.location.hostname || '');
  const providedDevNonce = CFG.devNonce ? String(CFG.devNonce) : '';
  const shouldUseDevNonce = isLocalhost || !!providedDevNonce;
  const devNonce = shouldUseDevNonce
    ? (providedDevNonce || `${Date.now()}-${Math.random().toString(16).slice(2)}`)
    : '';
  if (shouldUseDevNonce) {
    CFG.devNonce = devNonce;
  }
  const versionParam = assetVersion ? `v=${encodeURIComponent(assetVersion)}` : '';
  const devParam = devNonce ? `dev=${encodeURIComponent(devNonce)}` : '';
  const assetQuery = [versionParam, devParam].filter(Boolean).join('&');
  const assetSuffix = assetQuery ? `?${assetQuery}` : '';
  const moduleBaseUrl = CFG.pluginUrl ? `${CFG.pluginUrl}js/` : '';
  const importCalculator = (path) => {
    const cleanPath = String(path || '').replace(/^\.\//, '');
    const resolvedPath = moduleBaseUrl ? `${moduleBaseUrl}${cleanPath}` : path;
    return import(`${resolvedPath}${assetSuffix}`);
  };

  const CALCS = {
    'loan': el => importCalculator('./calculators/loan.js').then(m => mountWithTheme(m, el)),
    'mortgage': el => importCalculator('./calculators/mortgage.js').then(m => mountWithTheme(m, el)),
    'savings': el => importCalculator('./calculators/savings.js').then(m => mountWithTheme(m, el)),
    'bmi': el => importCalculator('./calculators/bmi.js').then(m => mountWithTheme(m, el)),
    'age': el => importCalculator('./calculators/age.js').then(m => mountWithTheme(m, el)),
    'unit-converter': el => importCalculator('./calculators/unit-converter.js').then(m => mountWithTheme(m, el)),
    'percentage': el => importCalculator('./calculators/percentage.js').then(m => mountWithTheme(m, el)),
    'tip': el => importCalculator('./calculators/tip.js').then(m => mountWithTheme(m, el)),
    'roi': el => importCalculator('./calculators/roi.js').then(m => mountWithTheme(m, el)),
    'credit-card-payoff': el => importCalculator('./calculators/credit-card-payoff.js').then(m => mountWithTheme(m, el)),
    'discount': el => importCalculator('./calculators/discount.js').then(m => mountWithTheme(m, el)),
    'fuel-cost': el => importCalculator('./calculators/fuel-cost.js').then(m => mountWithTheme(m, el)),
    'gpa': el => importCalculator('./calculators/gpa.js').then(m => mountWithTheme(m, el)),
    'grade-calc': el => importCalculator('./calculators/grade-calc.js').then(m => mountWithTheme(m, el)),
  };

  CALCS['compound-interest'] = CALCS['savings'];

  let chartLoadPromise = null;

  /**
   * Load Chart.js once when a calculator opts into chart assets.
   *
   * @returns {Promise<void>}
   */
  function loadChartJs() {
    if (chartLoadPromise) {
      return chartLoadPromise;
    }

    if (typeof window.Chart !== 'undefined') {
      chartLoadPromise = Promise.resolve();
      return chartLoadPromise;
    }

    chartLoadPromise = new Promise((resolve, reject) => {
      const script = document.createElement('script');
      const pluginUrl = CFG.pluginUrl || '';
      const version = assetVersion || CFG.version || '1';
      const chartQuery = assetQuery || `v=${encodeURIComponent(version)}`;
      script.src = pluginUrl + 'lib/chart.min.js' + (chartQuery ? `?${chartQuery}` : '');
      script.async = true;

      script.onload = () => {
        if (typeof window.Chart !== 'undefined') {
          resolve();
        } else {
          reject(new Error('Chart.js loaded but window.Chart is undefined'));
        }
      };

      script.onerror = () => {
        reject(new Error('Failed to load Chart.js'));
      };

      document.head.appendChild(script);
    });

    return chartLoadPromise;
  }

  const THEME_PRESETS = {
    light: {
      button_bg_color: '#2563eb',
      button_text_color: '#ffffff',
      button_hover_color: '#1d4ed8',
      card_bg_color: '#ffffff',
      card_border_color: '#e5e7eb',
      accent_color: '#3b82f6',
      input_bg_color: '#f9fafb',
      input_border_color: '#d1d5db',
      info_text_color: '#1e40af',
      info_bg_color: '#eff6ff',
      info_border_left_color: '#3b82f6',
      error_text_color: '#dc2626',
      error_bg_color: '#fef2f2',
      error_border_color: '#dc2626'
    },
    dark: {
      button_bg_color: '#60a5fa',
      button_text_color: '#ffffff',
      button_hover_color: '#93c5fd',
      card_bg_color: '#1f2937',
      card_border_color: '#374151',
      accent_color: '#60a5fa',
      input_bg_color: '#111827',
      input_border_color: '#374151',
      info_text_color: '#93c5fd',
      info_bg_color: '#1e3a5f',
      info_border_left_color: '#60a5fa',
      error_text_color: '#f87171',
      error_bg_color: '#450a0a',
      error_border_color: '#f87171'
    },
    modern: {
      button_bg_color: '#1e293b',
      button_text_color: '#ffffff',
      button_hover_color: '#334155',
      card_bg_color: '#ffffff',
      card_border_color: '#cbd5e1',
      accent_color: '#475569',
      input_bg_color: '#f8fafc',
      input_border_color: '#94a3b8',
      info_text_color: '#1e293b',
      info_bg_color: '#f1f5f9',
      info_border_left_color: '#475569',
      error_text_color: '#dc2626',
      error_bg_color: '#fef2f2',
      error_border_color: '#dc2626'
    }
  };

  function cleanupAutoCalc(node) {
    if (node && typeof node._autoCalcCleanup === 'function') {
      node._autoCalcCleanup();
      node._autoCalcCleanup = null;
    }
  }

  function disableAutoCalc(node) {
    if (!node) {
      return;
    }
    cleanupAutoCalc(node);
    delete node.dataset.autoCalculate;
    delete node.dataset.autoCalcDelay;
  }

  function enableAutoCalc(node, calcContent, delay) {
    if (!node || !calcContent) {
      return;
    }
    cleanupAutoCalc(node);

    node.dataset.autoCalculate = '1';
    node.dataset.autoCalcDelay = String(delay);

    let calcBtn = calcContent.querySelector('[data-vareoncalc-primary="true"]');
    if (!calcBtn) {
      calcBtn = calcContent.querySelector('.vareoncalc-btn');
    }
    if (!calcBtn) {
      calcBtn = calcContent.querySelector('button[type="button"]');
    }
    if (!calcBtn) {
      return;
    }

    const inputs = Array.from(calcContent.querySelectorAll('input, select'))
      .filter(input => input.dataset.vareoncalcAutoIgnore !== 'true');
    if (!inputs.length) {
      return;
    }

    let debounceTimer = null;
    const triggerCalc = () => {
      clearTimeout(debounceTimer);
      debounceTimer = setTimeout(() => {
        calcBtn.click();
      }, delay);
    };

    inputs.forEach(input => {
      input.addEventListener('input', triggerCalc);
      input.addEventListener('change', triggerCalc);
    });

    node._autoCalcCleanup = () => {
      inputs.forEach(input => {
        input.removeEventListener('input', triggerCalc);
        input.removeEventListener('change', triggerCalc);
      });
      node._autoCalcCleanup = null;
    };
  }

  function updateAutoCalcForNode(node, options = {}) {
    if (!node) {
      return;
    }
    const calcContent = node._vareoncalcContent || node.querySelector('.vareoncalc-content');
    if (!calcContent) {
      return;
    }

    const hasExplicitEnabled = Object.prototype.hasOwnProperty.call(options, 'enabled');
    const hasExplicitDelay = Object.prototype.hasOwnProperty.call(options, 'delay');
    const config = CFG.accessibility || {};

    const enabled = hasExplicitEnabled
      ? options.enabled
      : (node.dataset.autoCalculate === '1' || !!config.autoCalculate);

    const nodeDelayRaw = node.dataset.autoCalcDelay;
    const configHasDelay = Object.prototype.hasOwnProperty.call(config, 'autoCalculateDelay');
    const configDelayRaw = configHasDelay ? config.autoCalculateDelay : undefined;
    const delay = hasExplicitDelay
      ? normalizeAutoCalcDelay(options.delay)
      : normalizeAutoCalcDelay(typeof nodeDelayRaw !== 'undefined' ? nodeDelayRaw : configDelayRaw);

    if (enabled) {
      enableAutoCalc(node, calcContent, delay);
    } else {
      disableAutoCalc(node);
    }
  }

  const THEME_VARIABLES = [
    '--vareoncalc-button-bg',
    '--vareoncalc-button-text',
    '--vareoncalc-button-hover',
    '--vareoncalc-card-bg',
    '--vareoncalc-card-border',
    '--vareoncalc-card-text',
    '--vareoncalc-accent',
    '--vareoncalc-input-bg',
    '--vareoncalc-input-text',
    '--vareoncalc-input-border',
    '--vareoncalc-info',
    '--vareoncalc-info-text',
    '--vareoncalc-info-bg',
    '--vareoncalc-info-border-left',
    '--vareoncalc-error-text',
    '--vareoncalc-error-bg',
    '--vareoncalc-error-border',
    '--vareoncalc-border-width',
    '--vareoncalc-border-style',
    // Theme Studio token variables
    '--vareoncalc-focus-ring',
    '--vareoncalc-focus-shadow',
    '--vareoncalc-label-text',
    '--vareoncalc-muted-text',
    '--vareoncalc-link',
    '--vareoncalc-result-bg',
    '--vareoncalc-result-text',
    '--vareoncalc-result-border',
    '--vareoncalc-tip-bg',
    '--vareoncalc-tip-text',
    // Numeric token variables
    '--vareoncalc-border-radius',
    '--vareoncalc-card-padding',
    '--vareoncalc-field-mb',
    '--vareoncalc-row-gap',
    '--vareoncalc-out-padding',
    '--vareoncalc-card-shadow',
    '--vareoncalc-card-shadow-hover'
  ];

  function hexToRgb(hex) {
    const sanitized = hex.replace('#', '');
    if (sanitized.length !== 6) {
      return null;
    }
    const r = parseInt(sanitized.slice(0, 2), 16);
    const g = parseInt(sanitized.slice(2, 4), 16);
    const b = parseInt(sanitized.slice(4, 6), 16);
    if ([r, g, b].some(n => Number.isNaN(n))) {
      return null;
    }
    return { r, g, b };
  }

  function adjustBrightness(hex, percent) {
    const rgb = hexToRgb(hex);
    if (!rgb) {
      return hex;
    }
    const factor = percent / 100;
    const toHex = value => {
      const next = Math.min(255, Math.max(0, Math.round(value + value * factor)));
      return next.toString(16).padStart(2, '0');
    };
    return '#' + toHex(rgb.r) + toHex(rgb.g) + toHex(rgb.b);
  }

  function isLightColor(hex) {
    const rgb = hexToRgb(hex);
    if (!rgb) {
      return true;
    }
    const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
    return brightness > 155;
  }

  function parseRgbString(str) {
    if (!str) {
      return null;
    }
    const m = str.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
    if (!m) {
      return null;
    }
    return { r: parseInt(m[1], 10), g: parseInt(m[2], 10), b: parseInt(m[3], 10) };
  }

  function isTransparent(str) {
    if (!str || str === 'transparent' || str === 'rgba(0, 0, 0, 0)') {
      return true;
    }
    const m = str.match(/rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/);
    return m && parseFloat(m[1]) === 0;
  }

  function getAncestorBgRgb(el) {
    let node = el ? el.parentElement : null;
    while (node) {
      const bg = getComputedStyle(node).backgroundColor;
      if (bg && !isTransparent(bg)) {
        return parseRgbString(bg);
      }
      node = node.parentElement;
    }
    return null;
  }

  function isPageBgLight(el) {
    const rgb = getAncestorBgRgb(el);
    if (rgb) {
      return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 > 155;
    }
    return true;
  }

  /**
   * Generate a focus shadow CSS value from a focus color.
   * @param {string} hex Focus color hex value.
   * @returns {string} CSS box-shadow value.
   */
  function generateFocusShadow(hex) {
    const rgb = hexToRgb(hex);
    if (!rgb) {
      return '0 0 0 3px rgba(59, 130, 246, 0.3)';
    }
    return `0 0 0 3px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.3)`;
  }

  /**
   * Get spacing preset values based on preset index (0=tight, 1=normal, 2=relaxed).
   * @param {number} preset Preset index (0-2).
   * @returns {object} Object with padding, fieldMb, rowGap, outPadding values.
   */
  function getSpacingPresetValues(preset) {
    const presets = {
      0: { padding: '12px', fieldMb: '12px', rowGap: '8px', outPadding: '12px' },  // tight
      1: { padding: '16px', fieldMb: '14px', rowGap: '10px', outPadding: '14px' }, // normal
      2: { padding: '24px', fieldMb: '18px', rowGap: '14px', outPadding: '18px' }  // relaxed
    };
    return presets[preset] || presets[1];
  }

  /**
   * Get shadow CSS values based on intensity (0-3).
   * @param {number} intensity Shadow intensity (0=none, 1=soft, 2=medium, 3=strong).
   * @returns {object} Object with shadow and shadowHover values.
   */
  function getShadowIntensityValues(intensity) {
    const values = {
      0: { shadow: 'none', shadowHover: 'none' },
      1: { shadow: '0 1px 3px rgba(0, 0, 0, 0.08)', shadowHover: '0 2px 6px rgba(0, 0, 0, 0.12)' },
      2: { shadow: '0 4px 12px rgba(0, 0, 0, 0.08)', shadowHover: '0 6px 16px rgba(0, 0, 0, 0.12)' },
      3: { shadow: '0 8px 24px rgba(0, 0, 0, 0.12)', shadowHover: '0 12px 32px rgba(0, 0, 0, 0.16)' }
    };
    return values[intensity] || values[2];
  }

  /**
   * Get border radius CSS value from numeric value (0-24).
   * @param {number} radius Border radius in pixels.
   * @returns {string} CSS border-radius value.
   */
  function getBorderRadiusValue(radius) {
    return `${Math.max(0, Math.min(24, radius))}px`;
  }

  function clearTheme(root) {
    THEME_VARIABLES.forEach(variable => root.style.removeProperty(variable));
    delete root.dataset.vareoncalcTheme;
  }

  function applyTheme(root, themeId) {
    if (!root) {
      return;
    }
    const selected = THEME_PRESETS[themeId];
    if (!selected) {
      return;
    }

    const colors = selected.colors ? selected.colors : selected;
    const design = selected.design ? selected.design : selected;
    const buttonBg = colors.button_bg_color || '#3b82f6';
    const buttonText = colors.button_text_color || '#ffffff';
    const buttonHover = colors.button_hover_color || adjustBrightness(buttonBg, -10);
    const cardBg = colors.card_bg_color || '#ffffff';
    const cardBorder = colors.card_border_color || '#e5e7eb';
    const accent = colors.accent_color || buttonBg;
    const inputBg = colors.input_bg_color || '#f9fafb';
    const rawSelectBgLinked = (typeof colors.select_bg_linked !== 'undefined')
      ? colors.select_bg_linked
      : design.select_bg_linked;
    const selectBgLinked = (typeof rawSelectBgLinked === 'boolean')
      ? rawSelectBgLinked
      : (String(rawSelectBgLinked || '1') !== '0');
    const selectBg = selectBgLinked ? inputBg : (colors.select_bg_color || inputBg);
    const inputBorder = colors.input_border_color || '#d1d5db';
    const infoText = colors.info_text_color || accent;
    const infoBg = colors.info_bg_color || '#eff6ff';
    const infoBorder = colors.info_border_left_color || accent;
    const cardText = isLightColor(cardBg) ? '#111827' : '#f9fafb';
    const inputText = isLightColor(inputBg) ? '#111827' : '#f9fafb';
    const mutedText = isLightColor(cardBg) ? '#6b7280' : '#9ca3af';
    const labelText = cardText;
    const errorText = colors.error_text_color || (isLightColor(cardBg) ? '#dc2626' : '#f87171');
    const errorBg = colors.error_bg_color || (isLightColor(cardBg) ? '#fef2f2' : '#450a0a');
    const errorBorder = colors.error_border_color || errorText;

    root.style.setProperty('--vareoncalc-button-bg', buttonBg);
    root.style.setProperty('--vareoncalc-button-text', buttonText);
    root.style.setProperty('--vareoncalc-button-hover', buttonHover);
    root.style.setProperty('--vareoncalc-card-bg', cardBg);
    root.style.setProperty('--vareoncalc-card-border', cardBorder);
    root.style.setProperty('--vareoncalc-card-text', cardText);
    root.style.setProperty('--vareoncalc-accent', accent);
    root.style.setProperty('--vareoncalc-input-bg', inputBg);
    root.style.setProperty('--vareoncalc-input-text', inputText);
    root.style.setProperty('--vareoncalc-select-bg', selectBg);
    root.style.setProperty('--vareoncalc-input-border', inputBorder);
    root.style.setProperty('--vareoncalc-muted-text', mutedText);
    root.style.setProperty('--vareoncalc-label-text', labelText);
    root.style.setProperty('--vareoncalc-info-text', infoText);
    root.style.setProperty('--vareoncalc-info-bg', infoBg);
    root.style.setProperty('--vareoncalc-info-border-left', infoBorder);
    root.style.setProperty('--vareoncalc-error-text', errorText);
    root.style.setProperty('--vareoncalc-error-bg', errorBg);
    root.style.setProperty('--vareoncalc-error-border', errorBorder);
    root.dataset.vareoncalcTheme = themeId;
  }

  function resolveBrandingPreference(cfg) {
    if (cfg && typeof cfg.branding !== 'undefined') {
      return !!cfg.branding && cfg.branding !== '0' && cfg.branding !== 'false';
    }
    if (typeof CFG.branding !== 'undefined') {
      return !!CFG.branding && CFG.branding !== '0' && CFG.branding !== 'false';
    }
    return false;
  }

  /**
   * Resolve the effective card background color from config/theme.
   * Returns a hex color string or null if undetermined.
   */
  function resolveCardBgColor(cfg, root) {
    if (cfg && cfg.theme && THEME_PRESETS[cfg.theme]) {
      const themeColors = THEME_PRESETS[cfg.theme].colors || THEME_PRESETS[cfg.theme];
      if (themeColors.card_bg_color) {
        return themeColors.card_bg_color;
      }
    }
    if (cfg && cfg.colors && cfg.colors.card_bg_color) {
      return cfg.colors.card_bg_color;
    }
    if (root) {
      const cssVarBg = root.style.getPropertyValue('--vareoncalc-card-bg');
      if (cssVarBg) {
        return cssVarBg.trim();
      }
      const computedBg = getComputedStyle(root).getPropertyValue('--vareoncalc-card-bg').trim();
      if (computedBg) {
        return computedBg;
      }
    }
    return null;
  }

  /**
   * Pick the bundled logo variant that contrasts with the card surface.
   */
  function resolveLogoVariant(cfg, root) {
    const cardBg = resolveCardBgColor(cfg, root);
    if (cardBg) {
      return isLightColor(cardBg) ? 'light' : 'dark';
    }
    return 'light';
  }

  function isWizardActionButton(node) {
    if (!node || typeof node.matches !== 'function') {
      return false;
    }
    return node.matches('[data-wizard-back], [data-wizard-skip], [data-wizard-next], [data-wizard-finish], [data-wizard-restart]');
  }

  function ensureWizardNavBrandSlots(nav) {
    if (!(nav instanceof HTMLElement)) {
      return null;
    }

    nav.classList.add('vareoncalc-wizard__nav--branded');

    let left = null;
    let center = null;
    let right = null;
    Array.from(nav.children).forEach((child) => {
      if (!(child instanceof HTMLElement)) {
        return;
      }
      if (child.classList.contains('vareoncalc-wizard__nav-left')) {
        left = child;
      } else if (child.classList.contains('vareoncalc-wizard__nav-center')) {
        center = child;
      } else if (child.classList.contains('vareoncalc-wizard__nav-right')) {
        right = child;
      }
    });

    if (!left) {
      left = document.createElement('div');
      left.className = 'vareoncalc-wizard__nav-left';
    }
    if (!center) {
      center = document.createElement('div');
      center.className = 'vareoncalc-wizard__nav-center';
    }
    if (!right) {
      right = document.createElement('div');
      right.className = 'vareoncalc-wizard__nav-right';
    }

    const orderedButtons = Array.from(
      nav.querySelectorAll('[data-wizard-back], [data-wizard-skip], [data-wizard-next], [data-wizard-finish], [data-wizard-restart]')
    );
    orderedButtons.forEach((button) => {
      if (button.matches('[data-wizard-back]')) {
        left.appendChild(button);
      } else {
        right.appendChild(button);
      }
    });

    Array.from(nav.querySelectorAll('.vareoncalc-brand')).forEach((brand) => brand.remove());

    Array.from(nav.children).forEach((child) => {
      if (child === left || child === center || child === right) {
        return;
      }
      if (isWizardActionButton(child)) {
        return;
      }
      right.appendChild(child);
    });

    nav.appendChild(left);
    nav.appendChild(center);
    nav.appendChild(right);

    return { left, center, right };
  }

  function placeBrandOutsideCard(card, brand, root) {
    if (!card || !brand) {
      return;
    }
    const anchor = root || card;
    const parent = anchor.parentNode;
    if (!parent) {
      return;
    }
    if (anchor.nextSibling) {
      parent.insertBefore(brand, anchor.nextSibling);
    } else {
      parent.appendChild(brand);
    }
  }

  function buildBrandElement(logoVariant, className) {
    const brand = document.createElement('div');
    brand.className = className || 'vareoncalc-brand';

    const brandGrid = document.createElement('div');
    brandGrid.className = 'vareoncalc-brand-grid';
    brandGrid.style.justifyContent = 'center';
    brandGrid.style.gap = '8px';

    const brandDescription = document.createElement('div');
    brandDescription.className = 'vareoncalc-brand-description';

    const showText = typeof CFG.showBrandingText !== 'undefined' ? CFG.showBrandingText : true;
    if (showText) {
      /* translators: Branding text displayed before the logo */
      brandDescription.textContent = __('Powered by', 'vareon-calculator-suite-lite');
    } else {
      brandDescription.style.display = 'none';
    }

    const brandLogo = document.createElement('div');
    brandLogo.className = 'vareoncalc-brand-logo';
    brandLogo.style.justifyContent = 'center';
    brandLogo.style.marginLeft = '0';

    if (CFG.brandingLogo && CFG.brandingLogo.url) {
      brand.dataset.custom = 'true';
      // Branding fields are user-controlled, so build the logo with DOM APIs only.
      const logoHeight = Math.min(Math.max(parseInt(CFG.brandingLogo.height, 10) || 40, 20), 150);
      const logoLink = CFG.brandingLogo.link;

      const logoImg = document.createElement('img');
      logoImg.src = CFG.brandingLogo.url;
      logoImg.alt = CFG.brandingLogo.alt || '';
      logoImg.style.cssText = `height:${logoHeight}px;width:auto;max-width:100%;vertical-align:middle;transition:opacity 0.2s ease;`;

      if (logoLink) {
        const logoAnchor = document.createElement('a');
        logoAnchor.href = logoLink;
        logoAnchor.target = '_blank';
        logoAnchor.rel = 'noopener noreferrer';
        logoAnchor.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;color:inherit;padding:6px 10px;min-height:28px;box-sizing:border-box;cursor:pointer;pointer-events:auto;';
        logoAnchor.appendChild(logoImg);
        brandLogo.appendChild(logoAnchor);
      } else {
        const logoContainer = document.createElement('div');
        logoContainer.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:6px;padding:6px 10px;min-height:28px;box-sizing:border-box;';
        logoContainer.appendChild(logoImg);
        brandLogo.appendChild(logoContainer);
      }
    } else {
      const logoFile = 'vareon-logo.png';
      const pluginVersion = assetVersion || CFG.version || '1';
      const logoQuery = assetQuery || `v=${encodeURIComponent(pluginVersion)}`;
      const logoUrl = (CFG.pluginUrl || '') + 'assets/' + logoFile + (logoQuery ? `?${logoQuery}` : '');
      brand.dataset.logoVariant = logoVariant;

      const vareonAnchor = document.createElement('a');
      vareonAnchor.href = 'https://vareon.dev';
      vareonAnchor.target = '_blank';
      vareonAnchor.rel = 'noopener noreferrer';
      vareonAnchor.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;color:inherit;padding:6px 10px;min-height:28px;box-sizing:border-box;cursor:pointer;pointer-events:auto;';

      const vareonImg = document.createElement('img');
      vareonImg.src = logoUrl;
      vareonImg.alt = 'Vareon';
      vareonImg.style.cssText = 'height:32px;width:auto;vertical-align:middle;opacity:0.8;transition:opacity 0.2s ease;';

      vareonAnchor.appendChild(vareonImg);
      brandLogo.appendChild(vareonAnchor);
    }

    brandGrid.appendChild(brandDescription);
    brandGrid.appendChild(brandLogo);
    brand.appendChild(brandGrid);

    return brand;
  }

  function maybeRenderBranding(card, cfg) {
    if (!card) {
      return;
    }

    const root = card.closest('.vareoncalc-root');
    if (root) {
      Array.from(root.querySelectorAll('.vareoncalc-brand')).forEach((brandNode) => brandNode.remove());
      const nextSib = root.nextElementSibling;
      if (nextSib && nextSib.classList && nextSib.classList.contains('vareoncalc-brand')) {
        nextSib.remove();
      }
    } else {
      const existing = card.querySelector('.vareoncalc-brand');
      if (existing) {
        existing.remove();
      }
    }

    const showBranding = resolveBrandingPreference(cfg);
    if (!showBranding) {
      return;
    }

    const logoVariant = resolveLogoVariant(cfg, root);
    const wizard = card.querySelector('.vareoncalc-wizard[data-wizard], .vareoncalc-wizard');
    const wizardNav = wizard ? wizard.querySelector('.vareoncalc-wizard__nav') : null;
    const isWizard = !!wizardNav;

    const outsideClassName = isWizard
      ? 'vareoncalc-brand vareoncalc-brand--outside-card vareoncalc-brand--wizard-outside'
      : 'vareoncalc-brand vareoncalc-brand--outside-card';
    const pageLight = isPageBgLight(root || card);
    const outsideLogoVariant = pageLight ? 'light' : 'dark';
    const outsideBrand = buildBrandElement(outsideLogoVariant, outsideClassName);
    outsideBrand.style.color = pageLight ? '#6b7280' : '#d1d5db';
    outsideBrand.dataset.pageSurface = pageLight ? 'light' : 'dark';
    placeBrandOutsideCard(card, outsideBrand, root);

    if (!isWizard) {
      return;
    }

    const slots = ensureWizardNavBrandSlots(wizardNav);
    if (!slots || !slots.center) {
      return;
    }

    const navBrand = buildBrandElement(logoVariant, 'vareoncalc-brand vareoncalc-brand--wizard-nav');
    slots.center.appendChild(navBrand);
  }

  const observedNodes = new WeakSet();
  const layoutObservedNodes = new WeakSet();
  let mountObserver = null;
  let layoutRefreshObserver = null;
  const layoutRefreshDimensions = new WeakMap();

  function runLayoutRefresh(node) {
    if (!node || typeof node._vareoncalcRefreshLayout !== 'function') {
      return;
    }

    try {
      node._vareoncalcRefreshLayout();
    } catch {
      // Builders should not be able to break the calculator runtime.
    }
  }

  function ensureLayoutRefreshObserver() {
    if (typeof window === 'undefined' || typeof ResizeObserver === 'undefined') {
      return null;
    }

    if (!layoutRefreshObserver) {
      layoutRefreshObserver = new ResizeObserver(entries => {
        entries.forEach(entry => {
          const node = entry.target;
          if (!node) {
            return;
          }

          if (!node.isConnected) {
            layoutRefreshObserver.unobserve(node);
            layoutRefreshDimensions.delete(node);
            return;
          }

          const previous = layoutRefreshDimensions.get(node) || { width: 0, height: 0 };
          const nextWidth = Math.max(0, entry.contentRect?.width || 0);
          const nextHeight = Math.max(0, entry.contentRect?.height || 0);

          layoutRefreshDimensions.set(node, {
            width: nextWidth,
            height: nextHeight
          });

          const becameVisible = (previous.width <= 0 || previous.height <= 0)
            && (nextWidth > 0 || nextHeight > 0);
          const widthChanged = previous.width > 0 && Math.abs(nextWidth - previous.width) > 1;

          if (becameVisible || widthChanged) {
            runLayoutRefresh(node);
          }
        });
      });
    }

    return layoutRefreshObserver;
  }

  function observeLayoutRefresh(node) {
    const observer = ensureLayoutRefreshObserver();
    if (!observer || !node || layoutObservedNodes.has(node)) {
      return;
    }

    layoutObservedNodes.add(node);
    observer.observe(node);
  }

  function mountNode(node) {
    if (!node || node.dataset.vareoncalcReady || !node.dataset.config) {
      return;
    }

    try {
      node._vareoncalcRefreshLayout = null;
      const cfg = JSON.parse(node.dataset.config || '{}');

      while (node.firstChild) {
        node.removeChild(node.firstChild);
      }
      node.classList.remove('layout-wide');
      node.classList.remove('layout-compact');
      node.classList.add('vareoncalc-root');

      const a11y = CFG.accessibility || {};
      node.classList.toggle('vareoncalc-high-contrast', !!a11y.highContrast);
      node.classList.toggle('vareoncalc-keyboard-nav', !!a11y.keyboardNavigation);
      if (a11y.autoCalculate) {
        node.dataset.autoCalculate = '1';
        node.dataset.autoCalcDelay = String(normalizeAutoCalcDelay(a11y.autoCalculateDelay));
      }

      clearTheme(node);
      if (cfg.theme) {
        applyTheme(node, cfg.theme);
      }

      if (cfg.colors && typeof cfg.colors === 'object') {
        const colors = cfg.colors;
        const hasColor = value => typeof value === 'string' && hexToRgb(value) !== null;

        if (hasColor(colors.button_bg_color)) {
          node.style.setProperty('--vareoncalc-button-bg', colors.button_bg_color);
          const hoverColor = hasColor(colors.button_hover_color)
            ? colors.button_hover_color
            : adjustBrightness(colors.button_bg_color, -10);
          node.style.setProperty('--vareoncalc-button-hover', hoverColor);
        } else if (hasColor(colors.button_hover_color)) {
          node.style.setProperty('--vareoncalc-button-hover', colors.button_hover_color);
        }

        if (hasColor(colors.button_text_color)) {
          node.style.setProperty('--vareoncalc-button-text', colors.button_text_color);
        }

        if (hasColor(colors.card_bg_color)) {
          node.style.setProperty('--vareoncalc-card-bg', colors.card_bg_color);
          const cardText = hasColor(colors.card_text_color)
            ? colors.card_text_color
            : (isLightColor(colors.card_bg_color) ? '#111827' : '#f9fafb');
          node.style.setProperty('--vareoncalc-card-text', cardText);
        } else if (hasColor(colors.card_text_color)) {
          node.style.setProperty('--vareoncalc-card-text', colors.card_text_color);
        }

        if (hasColor(colors.card_border_color)) {
          node.style.setProperty('--vareoncalc-card-border', colors.card_border_color);
        }

        if (hasColor(colors.accent_color)) {
          node.style.setProperty('--vareoncalc-accent', colors.accent_color);
        }

        if (hasColor(colors.input_bg_color)) {
          node.style.setProperty('--vareoncalc-input-bg', colors.input_bg_color);
          const inputText = hasColor(colors.input_text_color)
            ? colors.input_text_color
            : (isLightColor(colors.input_bg_color) ? '#111827' : '#f9fafb');
          node.style.setProperty('--vareoncalc-input-text', inputText);
        } else if (hasColor(colors.input_text_color)) {
          node.style.setProperty('--vareoncalc-input-text', colors.input_text_color);
        }

        if (hasColor(colors.input_border_color)) {
          node.style.setProperty('--vareoncalc-input-border', colors.input_border_color);
        }

        if (hasColor(colors.info_text_color)) {
          node.style.setProperty('--vareoncalc-info-text', colors.info_text_color);
        }

        if (hasColor(colors.info_bg_color)) {
          node.style.setProperty('--vareoncalc-info-bg', colors.info_bg_color);
        }

        if (hasColor(colors.info_border_left_color)) {
          node.style.setProperty('--vareoncalc-info-border-left', colors.info_border_left_color);
          node.style.setProperty('--vareoncalc-info', colors.info_border_left_color);
        }

        if (hasColor(colors.error_text_color)) {
          node.style.setProperty('--vareoncalc-error-text', colors.error_text_color);
        }

        if (hasColor(colors.error_bg_color)) {
          node.style.setProperty('--vareoncalc-error-bg', colors.error_bg_color);
        }

        if (hasColor(colors.error_border_color)) {
          node.style.setProperty('--vareoncalc-error-border', colors.error_border_color);
        }

        const accent = colors.accent_color || '#3b82f6';

        if (hasColor(colors.focus_color)) {
          node.style.setProperty('--vareoncalc-focus-ring', colors.focus_color);
          node.style.setProperty('--vareoncalc-focus-shadow', generateFocusShadow(colors.focus_color));
        } else if (hasColor(accent)) {
          node.style.setProperty('--vareoncalc-focus-ring', accent);
          node.style.setProperty('--vareoncalc-focus-shadow', generateFocusShadow(accent));
        }

        if (hasColor(colors.label_color)) {
          node.style.setProperty('--vareoncalc-label-text', colors.label_color);
        }

        if (hasColor(colors.text_color)) {
          node.style.setProperty('--vareoncalc-card-text', colors.text_color);
        }

        if (hasColor(colors.muted_color)) {
          node.style.setProperty('--vareoncalc-muted-text', colors.muted_color);
        }

        if (hasColor(colors.link_color)) {
          node.style.setProperty('--vareoncalc-link', colors.link_color);
        }

        if (hasColor(colors.result_bg_color)) {
          node.style.setProperty('--vareoncalc-result-bg', colors.result_bg_color);
          const resultText = isLightColor(colors.result_bg_color) ? '#111827' : '#f9fafb';
          node.style.setProperty('--vareoncalc-result-text', resultText);
          node.style.setProperty('--vareoncalc-result-border', adjustBrightness(colors.result_bg_color, -15));
        }

        if (hasColor(colors.tip_bg_color)) {
          node.style.setProperty('--vareoncalc-tip-bg', colors.tip_bg_color);
          const tipText = isLightColor(colors.tip_bg_color) ? '#111827' : '#f9fafb';
          node.style.setProperty('--vareoncalc-tip-text', tipText);
        }
      }

      if (cfg.design && typeof cfg.design === 'object') {
        if (typeof cfg.design.card_border_radius === 'number' && cfg.design.card_border_radius >= 0) {
          node.style.setProperty('--vareoncalc-border-radius', getBorderRadiusValue(cfg.design.card_border_radius));
        }

        if (typeof cfg.design.shadow_intensity === 'number' && cfg.design.shadow_intensity >= 0) {
          const shadowValues = getShadowIntensityValues(cfg.design.shadow_intensity);
          node.style.setProperty('--vareoncalc-card-shadow', shadowValues.shadow);
          node.style.setProperty('--vareoncalc-card-shadow-hover', shadowValues.shadowHover);
        }

        if (typeof cfg.design.spacing_preset === 'number' && cfg.design.spacing_preset >= 0) {
          const spacingValues = getSpacingPresetValues(cfg.design.spacing_preset);
          node.style.setProperty('--vareoncalc-card-padding', spacingValues.padding);
          node.style.setProperty('--vareoncalc-field-mb', spacingValues.fieldMb);
          node.style.setProperty('--vareoncalc-row-gap', spacingValues.rowGap);
          node.style.setProperty('--vareoncalc-out-padding', spacingValues.outPadding);
        }
      }

      const card = document.createElement('div');
      card.className = 'vareoncalc-card';

      let cardBgColor = null;

      if (cfg.theme && THEME_PRESETS[cfg.theme]) {
        const themeColors = THEME_PRESETS[cfg.theme].colors || THEME_PRESETS[cfg.theme];
        cardBgColor = themeColors.card_bg_color || '#ffffff';
      } else if (cfg.colors && cfg.colors.card_bg_color) {
        cardBgColor = cfg.colors.card_bg_color;
      } else {
        const cssVarBg = node.style.getPropertyValue('--vareoncalc-card-bg');
        if (cssVarBg) {
          cardBgColor = cssVarBg.trim();
        } else {
          const computedBg = getComputedStyle(node).getPropertyValue('--vareoncalc-card-bg').trim();
          if (computedBg) {
            cardBgColor = computedBg;
          }
        }
      }

      // Keep explicit built-in presets such as modern even when custom colors are still light.
      const requestedTheme = typeof cfg.theme === 'string' ? cfg.theme : '';
      const hasKnownTheme = !!(requestedTheme && THEME_PRESETS[requestedTheme]);
      const effectiveDark = cardBgColor ? !isLightColor(cardBgColor) : (cfg.theme === 'dark');
      const surfaceTheme = hasKnownTheme ? requestedTheme : (effectiveDark ? 'dark' : 'light');
      node.dataset.theme = surfaceTheme;
      node.classList.toggle('theme-dark', surfaceTheme === 'dark');

      node.appendChild(card);

      if (cfg.design && typeof cfg.design === 'object') {
        if (card) {
          ['vareoncalc-border-none', 'vareoncalc-border-thin', 'vareoncalc-border-medium', 'vareoncalc-border-thick']
            .forEach(cls => card.classList.remove(cls));
          ['vareoncalc-borderstyle-solid', 'vareoncalc-borderstyle-dashed', 'vareoncalc-borderstyle-dotted']
            .forEach(cls => card.classList.remove(cls));
        }

        const borderWidth = cfg.design.border_width;
        if (borderWidth) {
          const borderWidthMap = {
            none: '0px',
            thin: '1px',
            medium: '2px',
            thick: '3px'
          };
          const borderWidthValue = borderWidthMap[borderWidth] || borderWidthMap.thin;
          node.style.setProperty('--vareoncalc-border-width', borderWidthValue);

          if (card && ['none', 'thin', 'medium', 'thick'].includes(borderWidth)) {
            card.classList.add('vareoncalc-border-' + borderWidth);
          }
        }

        const borderStyle = cfg.design.border_style;
        if (borderStyle && ['solid', 'dashed', 'dotted'].includes(borderStyle)) {
          node.style.setProperty('--vareoncalc-border-style', borderStyle);

          if (card) {
            card.classList.add('vareoncalc-borderstyle-' + borderStyle);
          }
        }

        const cornerRadius = cfg.design.corner_radius;
        if (cornerRadius && ['sharp', 'soft', 'rounded', 'pill'].includes(cornerRadius)) {
          node.classList.remove('vareoncalc-radius-sharp', 'vareoncalc-radius-soft', 'vareoncalc-radius-rounded', 'vareoncalc-radius-pill');
          node.classList.add('vareoncalc-radius-' + cornerRadius);
        }

        const shadowStyle = cfg.design.shadow_style;
        if (shadowStyle && ['none', 'soft', 'medium', 'strong'].includes(shadowStyle)) {
          node.classList.remove('vareoncalc-shadow-none', 'vareoncalc-shadow-soft', 'vareoncalc-shadow-medium', 'vareoncalc-shadow-strong');
          node.classList.add('vareoncalc-shadow-' + shadowStyle);
        }

        const spacingDensity = cfg.design.spacing_density;
        if (spacingDensity && ['tight', 'normal', 'relaxed'].includes(spacingDensity)) {
          node.classList.remove('vareoncalc-spacing-tight', 'vareoncalc-spacing-normal', 'vareoncalc-spacing-relaxed');
          node.classList.add('vareoncalc-spacing-' + spacingDensity);
        }

        const buttonStyle = cfg.design.button_style;
        if (buttonStyle && ['solid', 'outline', 'ghost', 'gradient'].includes(buttonStyle)) {
          node.classList.remove('vareoncalc-button-solid', 'vareoncalc-button-outline', 'vareoncalc-button-ghost', 'vareoncalc-button-gradient');
          node.classList.add('vareoncalc-button-' + buttonStyle);
        }

        const inputStyle = cfg.design.input_style || 'standard';
        if (['standard', 'filled', 'outlined', 'underlined'].includes(inputStyle)) {
          node.classList.remove('vareoncalc-input-standard', 'vareoncalc-input-filled', 'vareoncalc-input-outlined', 'vareoncalc-input-underlined');
          node.classList.add('vareoncalc-input-' + inputStyle);
        }
      }

      if (node._vareoncalcFormatter && typeof node._vareoncalcFormatter.disconnect === 'function') {
        node._vareoncalcFormatter.disconnect();
      }
      node._vareoncalcFormatter = observeCurrencyFormatting(node);

      // Calculators can replace their mount node, so keep their content inside a dedicated wrapper.
      const calcContent = document.createElement('div');
      calcContent.className = 'vareoncalc-content';
      card.appendChild(calcContent);

      const type = cfg.type || 'bmi';
      const loader = CALCS[type] || CALCS['bmi'];
      node._vareoncalcContent = calcContent;
      calcContent.dataset.vareoncalcType = type;

      const needsChart = cfg.assets && cfg.assets.chart === true;

      const loadResult = needsChart
        ? loadChartJs().then(() => loader(calcContent))
        : loader(calcContent);

      const initialAutoCalcEnabled = !!node.dataset.autoCalculate || !!a11y.autoCalculate;
      const initialDelayRaw = typeof node.dataset.autoCalcDelay !== 'undefined' ? node.dataset.autoCalcDelay : a11y.autoCalculateDelay;
      const initialAutoCalcDelay = normalizeAutoCalcDelay(initialDelayRaw);

      const finalizeMount = () => {
        maybeRenderBranding(card, cfg);
        updateAutoCalcForNode(node, {
          enabled: initialAutoCalcEnabled,
          delay: initialAutoCalcDelay
        });
      };

      if (loadResult && typeof loadResult.then === 'function') {
        loadResult.then(function () {
          finalizeMount();
          observeLayoutRefresh(node);
        }).catch(function (error) {
          if (card) {
            const errorDiv = document.createElement('div');
            errorDiv.className = 'vareoncalc-error';
            errorDiv.style.cssText = 'padding: 20px; color: var(--sc-error, #dc2626); text-align: center;';

            const errorTitle = document.createElement('p');
            errorTitle.style.cssText = 'font-weight: bold; margin-bottom: 8px;';
            /* translators: Error message shown when a calculator fails to load */
            errorTitle.textContent = __('Failed to load calculator', 'vareon-calculator-suite-lite');

            const errorPre = document.createElement('pre');
            errorPre.style.cssText = 'font-size: 11px; background: var(--sc-error-bg, #fef2f2); padding: 8px; border-radius: 4px; overflow: auto; max-width: 100%; text-align: left;';
            errorPre.textContent = error.message || String(error);

            errorDiv.appendChild(errorTitle);
            errorDiv.appendChild(errorPre);

            while (card.firstChild) {
              card.removeChild(card.firstChild);
            }
            card.appendChild(errorDiv);
          }
        });
      } else {
        finalizeMount();
        observeLayoutRefresh(node);
      }

      node.dataset.vareoncalcReady = '1';
    } catch {
      if (node) {
        while (node.firstChild) {
          node.removeChild(node.firstChild);
        }
        const errorEm = document.createElement('em');
        /* translators: Generic error message shown when calculator encounters an error */
        errorEm.textContent = __('Vareon Calculator error', 'vareon-calculator-suite-lite');
        node.appendChild(errorEm);
      }
    } finally {
      observedNodes.delete(node);
    }
  }

  function ensureObserver() {
    if (typeof window === 'undefined' || !('IntersectionObserver' in window)) {
      return null;
    }

    if (!mountObserver) {
      mountObserver = new IntersectionObserver(entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            mountObserver.unobserve(entry.target);
            mountNode(entry.target);
          }
        });
      }, {
        root: null,
        rootMargin: '200px 0px',
        threshold: 0.01
      });
    }

    return mountObserver;
  }

  function scheduleMount(node) {
    const observer = ensureObserver();
    if (!observer) {
      mountNode(node);
      return;
    }

    if (!observedNodes.has(node) && !node.dataset.vareoncalcReady) {
      observedNodes.add(node);
      observer.observe(node);
    }
  }

  function getMountTargets(root) {
    if (!root) {
      return [];
    }

    const nodes = [];
    const appendNode = candidate => {
      if (
        candidate
        && candidate.nodeType === 1
        && typeof candidate.matches === 'function'
        && candidate.matches('.vareoncalc[data-config]')
      ) {
        nodes.push(candidate);
      }
    };

    appendNode(root);

    if (typeof root.querySelectorAll === 'function') {
      root.querySelectorAll('.vareoncalc[data-config]').forEach(appendNode);
    }

    return nodes;
  }

  function getReadyMountTargets(root) {
    if (!root) {
      return [];
    }

    const nodes = [];
    const appendNode = candidate => {
      if (
        candidate
        && candidate.nodeType === 1
        && typeof candidate.matches === 'function'
        && candidate.matches('.vareoncalc-root[data-vareoncalc-ready="1"]')
      ) {
        nodes.push(candidate);
      }
    };

    appendNode(root);

    if (typeof root.querySelectorAll === 'function') {
      root.querySelectorAll('.vareoncalc-root[data-vareoncalc-ready="1"]').forEach(appendNode);
    }

    return nodes;
  }

  function mountNodes(nodes, options = {}) {
    if (options.useObserver) {
      const observer = ensureObserver();
      if (!observer) {
        nodes.forEach(mountNode);
        return;
      }
      nodes.forEach(scheduleMount);
      return;
    }

    nodes.forEach(mountNode);
  }

  function mountWithin(root, options = {}) {
    mountNodes(getMountTargets(root), options);
  }

  function mountAll(options = {}) {
    mountWithin(document, options);
  }

  let dynamicRootObserver = null;
  const pendingDynamicNodes = new Set();
  let pendingDynamicMountFrame = 0;

  function flushDynamicMounts() {
    pendingDynamicMountFrame = 0;
    if (!pendingDynamicNodes.size) {
      return;
    }

    const nodes = Array.from(pendingDynamicNodes);
    pendingDynamicNodes.clear();
    mountNodes(nodes, { useObserver: true });
  }

  function queueDynamicMount(node) {
    if (!node || node.dataset?.vareoncalcReady) {
      return;
    }

    pendingDynamicNodes.add(node);
    if (pendingDynamicMountFrame) {
      return;
    }

    if (typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function') {
      pendingDynamicMountFrame = window.requestAnimationFrame(flushDynamicMounts);
      return;
    }

    pendingDynamicMountFrame = window.setTimeout(flushDynamicMounts, 0);
  }

  function observeDynamicMounts() {
    if (dynamicRootObserver || typeof MutationObserver === 'undefined') {
      return;
    }

    const root = document.body || document.documentElement;
    if (!root) {
      return;
    }

    dynamicRootObserver = new MutationObserver(mutations => {
      mutations.forEach(mutation => {
        if (mutation.type === 'attributes') {
          getMountTargets(mutation.target).forEach(queueDynamicMount);
          return;
        }

        mutation.addedNodes.forEach(addedNode => {
          if (!addedNode || addedNode.nodeType !== 1) {
            return;
          }

          getMountTargets(addedNode).forEach(queueDynamicMount);
        });
      });
    });

    dynamicRootObserver.observe(root, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['data-config']
    });
  }

  window.vareoncalcMountAll = (options = {}) => {
    if (options === true || (options && typeof options === 'object' && options.useObserver)) {
      mountAll({ useObserver: true });
    } else {
      mountAll();
    }
  };

  window.vareoncalcMountWithin = (root, options = {}) => {
    if (options === true || (options && typeof options === 'object' && options.useObserver)) {
      mountWithin(root || document, { useObserver: true });
      return;
    }

    mountWithin(root || document, options);
  };

  window.vareoncalcMount = mountNode;
  window.vareoncalcPreviewMount = mountNode;

  window.vareoncalcRefreshLayout = (targetNode) => {
    getReadyMountTargets(targetNode || document).forEach(runLayoutRefresh);
  };

  window.vareoncalcUpdateAutoCalc = (options = {}) => {
    CFG.accessibility = CFG.accessibility || {};

    const hasEnabled = Object.prototype.hasOwnProperty.call(options, 'enabled');
    const hasDelay = Object.prototype.hasOwnProperty.call(options, 'delay');

    if (hasEnabled) {
      CFG.accessibility.autoCalculate = !!options.enabled;
    }
    if (hasDelay) {
      CFG.accessibility.autoCalculateDelay = normalizeAutoCalcDelay(options.delay);
    }

    const updateOptions = {};
    if (hasEnabled) {
      updateOptions.enabled = !!options.enabled;
    }
    if (hasDelay) {
      updateOptions.delay = CFG.accessibility.autoCalculateDelay;
    }

    document.querySelectorAll('.vareoncalc-root[data-vareoncalc-ready="1"]').forEach(node => {
      updateAutoCalcForNode(node, updateOptions);
    });
  };

  window.vareoncalcRefreshAutoCalc = (targetNode) => {
    if (targetNode) {
      updateAutoCalcForNode(targetNode);
      return;
    }
    document.querySelectorAll('.vareoncalc-root[data-vareoncalc-ready="1"]').forEach(node => {
      updateAutoCalcForNode(node);
    });
  };

  document.addEventListener('vareoncalc:mount', event => {
    const detailRoot = event?.detail?.root || event?.target || document;
    mountWithin(detailRoot, { useObserver: true });
    window.vareoncalcRefreshLayout(detailRoot);
  });

  // Mount on DOM ready; calculator modules are still loaded per type.
  const autoMount = () => {
    mountAll();
    observeDynamicMounts();
  };
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', autoMount);
  } else {
    autoMount();
  }
})();
