(function (global, factory) {
  'use strict';

  var api = factory();

  if (typeof module === 'object' && module.exports) {
    module.exports = api;
  }

  if (global && global.document) {
    global.NabytkarstvoDivaFabricPilot = api;
    api.boot(global);
  }
})(typeof window !== 'undefined' ? window : null, function () {
  'use strict';

  var PRODUCT_ID = '8162';
  var EXPECTED_MAKER = 'New Design';
  var EXPECTED_FABRIC_COUNT = 147;
  var CATALOG_URLS = [
    '/show-free.htm?fid=110',
    '/potahove-latky-new-design'
  ];
  var LEG_SHAPE_SPRITE_URL = '/fotky13204/tvar%20ozdobnych%20noh.jpg';
  var LEG_FINISH_SPRITE_URL = '/fotky13204/moreni%20noh%20sk.jpg';
  var LEG_SHAPES = [
    { code: '0', label: 'Noha č. 0', height: '6 cm' },
    { code: '1', label: 'Noha č. 1', height: '6 cm' },
    { code: '2', label: 'Noha č. 2', height: '6 cm' },
    { code: '3', label: 'Noha č. 3', height: '12 cm' },
    { code: '4', label: 'Noha č. 4', height: '12 cm' },
    { code: '5', label: 'Noha č. 5', height: '12 cm' },
    { code: '6', label: 'Noha č. 6', height: '12 cm' }
  ];
  var LEG_FINISHES = [
    { code: 'A', key: 'prirodna', label: 'Prírodná' },
    { code: 'B', key: 'morenie ceresna', label: 'Morenie čerešňa' },
    { code: 'C', key: 'morenie orech', label: 'Morenie orech' },
    { code: 'D', key: 'morenie strieborne', label: 'Morenie strieborné' },
    { code: 'E', key: 'morenie cierne', label: 'Morenie čierne' },
    { code: 'F', key: 'chrom', label: 'Chróm', chrome: true }
  ];
  var TOPPER_KEYS = ['none', 'standard', 'aero'];

  function normalizeText(value) {
    var text = String(value == null ? '' : value);

    if (typeof text.normalize === 'function') {
      text = text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
    }

    return text
      .replace(/\u00a0/g, ' ')
      .replace(/[^a-zA-Z0-9]+/g, ' ')
      .trim()
      .toLowerCase()
      .replace(/\s+/g, ' ');
  }

  function legCombinationKey(shapeCode, finishKey) {
    return String(shapeCode) + '|' + String(finishKey);
  }

  function parseLegOptionLabel(value) {
    var label = normalizeText(value);
    var match = /^noha c ([0-6]) (.+)$/.exec(label);
    var finish = null;

    if (!match) {
      return null;
    }

    LEG_FINISHES.some(function (candidate) {
      if (match[2] === candidate.key) {
        finish = candidate;
        return true;
      }
      return false;
    });

    if (!finish || (finish.chrome && match[1] !== '2' && match[1] !== '4')) {
      return null;
    }

    return {
      shape: match[1],
      finish: finish.key,
      finishCode: finish.code,
      key: legCombinationKey(match[1], finish.key)
    };
  }

  function parseTopperOptionLabel(value) {
    var label = normalizeText(value);

    if (label === 'bez toppera') {
      return { key: 'none' };
    }
    if (/^s topperom(?: |$)/.test(label)) {
      return { key: 'standard' };
    }
    if (/^topper aero(?: |$)/.test(label)) {
      return { key: 'aero' };
    }

    return null;
  }

  function isPlaceholderText(value) {
    var label = normalizeText(value);

    return !label ||
      /(^| )kliknite( |$).*\bvyber\b/.test(label) ||
      /(^| )(vyberte|zvolte)( |$)/.test(label) ||
      label === 'vyber' ||
      label === 'bez vyberu';
  }

  function hasToken(haystack, token) {
    return (' ' + haystack + ' ').indexOf(' ' + token + ' ') !== -1;
  }

  function scoreOptionLabel(optionLabel, fabric) {
    var label = normalizeText(optionLabel);
    var name = normalizeText(fabric && fabric.name);
    var maker = normalizeText(fabric && fabric.maker ? fabric.maker : EXPECTED_MAKER);
    var code = normalizeText(fabric && fabric.code);

    if (!label || !code || isPlaceholderText(label)) {
      return 0;
    }

    if (name && label === name) {
      return 100;
    }

    if (name && label.indexOf(name + ' ') === 0) {
      return 95;
    }

    if (label === code) {
      return 80;
    }

    if (hasToken(label, code) && maker && label.indexOf(maker) !== -1) {
      return 75;
    }

    return 0;
  }

  function findOptionForFabric(options, fabric) {
    var best = null;
    var bestScore = 0;
    var bestCount = 0;

    Array.prototype.forEach.call(options || [], function (option) {
      var score = scoreOptionLabel(option.textContent || option.label || '', fabric);
      if (score > bestScore) {
        best = option;
        bestScore = score;
        bestCount = 1;
      } else if (score > 0 && score === bestScore) {
        bestCount += 1;
      }
    });

    return bestCount === 1 ? best : null;
  }

  function findFabricForOption(option, fabrics) {
    var best = null;
    var bestScore = 0;
    var bestCount = 0;

    (fabrics || []).forEach(function (fabric) {
      var score = scoreOptionLabel(option && (option.textContent || option.label || ''), fabric);
      if (score > bestScore) {
        best = fabric;
        bestScore = score;
        bestCount = 1;
      } else if (score > 0 && score === bestScore) {
        bestCount += 1;
      }
    });

    return bestCount === 1 ? best : null;
  }

  function findPlaceholderOption(select) {
    var found = null;

    Array.prototype.some.call(select.options || [], function (option) {
      if (isPlaceholderText(option.textContent || option.label || '')) {
        found = option;
        return true;
      }
      return false;
    });

    if (!found && select.options && select.options.length) {
      var first = select.options[0];
      if (!String(first.value || '').trim() || first.disabled || first.hidden) {
        found = first;
      }
    }

    return found;
  }

  function hasValidSelection(select, placeholderOption) {
    if (!select || select.selectedIndex < 0) {
      return false;
    }

    var selected = select.options[select.selectedIndex];
    if (!selected || selected.disabled || isPlaceholderText(selected.textContent || selected.label || '')) {
      return false;
    }

    return !placeholderOption || selected !== placeholderOption;
  }

  function validateCatalogFabrics(fabrics) {
    if (!Array.isArray(fabrics) || fabrics.length !== EXPECTED_FABRIC_COUNT) {
      throw new Error('Vzorkovník musí obsahovať presne ' + EXPECTED_FABRIC_COUNT + ' látok.');
    }

    var seenCodes = Object.create(null);
    fabrics.forEach(function (fabric) {
      var code = normalizeText(fabric && fabric.code);
      if (!code || seenCodes[code]) {
        throw new Error('Vzorkovník obsahuje prázdny alebo duplicitný kód látky.');
      }
      if (normalizeText(fabric.maker) !== normalizeText(EXPECTED_MAKER)) {
        throw new Error('Vzorkovník obsahuje látku iného výrobcu.');
      }
      seenCodes[code] = true;
    });

    return fabrics;
  }

  function buildStrictMapping(select, fabrics) {
    validateCatalogFabrics(fabrics);

    var options = Array.prototype.slice.call(select.options || []);
    var placeholders = options.filter(function (option) {
      return isPlaceholderText(option.textContent || option.label || '');
    });

    if (placeholders.length !== 1) {
      throw new Error('Systémový číselník musí obsahovať práve jeden rozpoznateľný placeholder.');
    }

    var realOptions = options.filter(function (option) {
      return option !== placeholders[0];
    });
    if (realOptions.length !== EXPECTED_FABRIC_COUNT) {
      throw new Error('Systémový číselník musí obsahovať presne ' + EXPECTED_FABRIC_COUNT + ' látok.');
    }

    var seenValues = Object.create(null);
    realOptions.forEach(function (option) {
      var value = String(option.value == null ? '' : option.value);
      if (!value || seenValues[value]) {
        throw new Error('Systémový číselník obsahuje prázdne alebo duplicitné ID hodnoty.');
      }
      seenValues[value] = true;
    });

    var optionByCode = Object.create(null);
    var fabricByValue = Object.create(null);
    var usedOptions = [];

    fabrics.forEach(function (fabric) {
      var matches = realOptions.filter(function (option) {
        return scoreOptionLabel(option.textContent || option.label || '', fabric) > 0;
      });

      if (matches.length !== 1 || usedOptions.indexOf(matches[0]) !== -1) {
        throw new Error('Látka ' + fabric.name + ' nemá jednoznačnú systémovú hodnotu.');
      }

      var option = matches[0];
      usedOptions.push(option);
      optionByCode[normalizeText(fabric.code)] = option;
      fabricByValue[String(option.value)] = fabric;
    });

    if (usedOptions.length !== realOptions.length) {
      throw new Error('Nie všetky systémové hodnoty majú jednoznačný pár vo vzorkovníku.');
    }

    return {
      placeholder: placeholders[0],
      optionByCode: optionByCode,
      fabricByValue: fabricByValue
    };
  }

  function expectedLegCombinationKeys() {
    var keys = [];

    LEG_SHAPES.forEach(function (shape) {
      LEG_FINISHES.forEach(function (finish) {
        if (!finish.chrome || shape.code === '2' || shape.code === '4') {
          keys.push(legCombinationKey(shape.code, finish.key));
        }
      });
    });

    return keys;
  }

  function buildStrictLegMapping(select) {
    var options = Array.prototype.slice.call(select && select.options || []);
    var placeholders = options.filter(function (option) {
      return isPlaceholderText(option.textContent || option.label || '');
    });
    var expectedKeys = expectedLegCombinationKeys();
    var optionByKey = Object.create(null);
    var legByValue = Object.create(null);
    var seenValues = Object.create(null);

    if (placeholders.length !== 1) {
      throw new Error('Systémový číselník nožičiek musí obsahovať práve jeden rozpoznateľný placeholder.');
    }

    var realOptions = options.filter(function (option) {
      return option !== placeholders[0];
    });

    if (realOptions.length !== expectedKeys.length) {
      throw new Error('Systémový číselník nožičiek musí obsahovať presne ' + expectedKeys.length + ' kombinácií.');
    }

    realOptions.forEach(function (option) {
      var value = String(option.value == null ? '' : option.value);
      var leg = parseLegOptionLabel(option.textContent || option.label || '');

      if (!value || seenValues[value]) {
        throw new Error('Systémový číselník nožičiek obsahuje prázdne alebo duplicitné ID hodnoty.');
      }
      if (option.disabled || !leg) {
        throw new Error('Systémový číselník nožičiek obsahuje neznámu alebo nedostupnú kombináciu.');
      }
      if (optionByKey[leg.key]) {
        throw new Error('Systémový číselník nožičiek obsahuje duplicitnú kombináciu.');
      }

      seenValues[value] = true;
      optionByKey[leg.key] = option;
      legByValue[value] = leg;
    });

    expectedKeys.forEach(function (key) {
      if (!optionByKey[key]) {
        throw new Error('Systémový číselník nožičiek neobsahuje všetky očakávané kombinácie.');
      }
    });

    return {
      placeholder: placeholders[0],
      optionByKey: optionByKey,
      legByValue: legByValue
    };
  }

  function buildStrictTopperMapping(select) {
    var options = Array.prototype.slice.call(select && select.options || []);
    var placeholders = options.filter(function (option) {
      return isPlaceholderText(option.textContent || option.label || '');
    });
    var optionByKey = Object.create(null);
    var topperByValue = Object.create(null);
    var seenValues = Object.create(null);

    if (placeholders.length !== 1) {
      throw new Error('Systémový číselník toppera musí obsahovať práve jeden rozpoznateľný placeholder.');
    }

    var realOptions = options.filter(function (option) {
      return option !== placeholders[0];
    });

    if (realOptions.length !== TOPPER_KEYS.length) {
      throw new Error('Systémový číselník toppera musí obsahovať presne tri možnosti.');
    }

    realOptions.forEach(function (option) {
      var value = String(option.value == null ? '' : option.value);
      var topper = parseTopperOptionLabel(option.textContent || option.label || '');

      if (!value || seenValues[value]) {
        throw new Error('Systémový číselník toppera obsahuje prázdne alebo duplicitné ID hodnoty.');
      }
      if (option.disabled || !topper || optionByKey[topper.key]) {
        throw new Error('Systémový číselník toppera obsahuje neznámu, duplicitnú alebo nedostupnú možnosť.');
      }

      seenValues[value] = true;
      optionByKey[topper.key] = option;
      topperByValue[value] = topper;
    });

    TOPPER_KEYS.forEach(function (key) {
      if (!optionByKey[key]) {
        throw new Error('Systémový číselník toppera neobsahuje všetky očakávané možnosti.');
      }
    });

    return {
      placeholder: placeholders[0],
      optionByKey: optionByKey,
      topperByValue: topperByValue
    };
  }

  function safeSameOriginUrl(reference, locationObject) {
    if (!reference) {
      return null;
    }

    try {
      var resolved = new URL(reference, locationObject.href);
      return resolved.origin === locationObject.origin ? resolved.href : null;
    } catch (error) {
      return null;
    }
  }

  function parseCatalogDocument(documentObject, locationObject) {
    var root = documentObject.querySelector('[data-fabric-catalog]');
    if (!root) {
      throw new Error('Na stránke chýba blok data-fabric-catalog.');
    }

    var maker = (root.getAttribute('data-fabric-maker') || EXPECTED_MAKER).trim();
    if (normalizeText(maker) !== normalizeText(EXPECTED_MAKER)) {
      throw new Error('Vzorkovník patrí inému výrobcovi.');
    }

    var seen = Object.create(null);
    var fabrics = [];

    Array.prototype.forEach.call(root.querySelectorAll('[data-fabric-preview][data-fabric-code]'), function (anchor) {
      var image = anchor.querySelector('img');
      var code = String(anchor.getAttribute('data-fabric-code') || '').trim();
      var normalizedCode = normalizeText(code);
      var hybrid = image && safeSameOriginUrl(image.getAttribute('src'), locationObject);
      var large = safeSameOriginUrl(anchor.getAttribute('href'), locationObject);

      if (!normalizedCode || !hybrid || !large) {
        throw new Error('Vzorka nemá platný kód alebo obrázky z rovnakej domény.');
      }

      if (seen[normalizedCode]) {
        throw new Error('Vzorkovník obsahuje duplicitný kód ' + code + '.');
      }

      seen[normalizedCode] = true;
      fabrics.push({
        code: code,
        maker: maker,
        name: maker + ' ' + code,
        hybrid: hybrid,
        large: large
      });
    });

    return validateCatalogFabrics(fabrics);
  }

  function dispatchNativeEvent(globalObject, element, type) {
    var event;
    try {
      event = new globalObject.Event(type, { bubbles: true });
    } catch (error) {
      event = globalObject.document.createEvent('Event');
      event.initEvent(type, true, false);
    }
    element.dispatchEvent(event);
  }

  function element(documentObject, tagName, className, text) {
    var node = documentObject.createElement(tagName);
    if (className) {
      node.className = className;
    }
    if (text != null) {
      node.textContent = text;
    }
    return node;
  }

  function numberedHeading(documentObject, className, number, label) {
    var heading = element(documentObject, 'p', className);
    var badge = element(documentObject, 'b', '', String(number));
    heading.appendChild(badge);
    heading.appendChild(documentObject.createTextNode(label));
    return heading;
  }

  function makeCatalogLink(documentObject) {
    var link = element(documentObject, 'a', 'ndp-catalog-link', 'Otvoriť celý vzorkovník');
    link.href = CATALOG_URLS[0];
    link.target = '_blank';
    link.rel = 'noopener';
    return link;
  }

  function getProductForm(documentObject) {
    var forms = documentObject.querySelectorAll('form[action*="buy-product.htm"]');
    var match = null;

    Array.prototype.some.call(forms, function (form) {
      var action = form.getAttribute('action') || '';
      if (/(?:[?&])pid=8162(?:&|$)/.test(action)) {
        match = form;
        return true;
      }
      return false;
    });

    return match;
  }

  function manufacturerEvidenceMatches(values) {
    return (values || []).some(function (value) {
      return normalizeText(value) === normalizeText(EXPECTED_MAKER);
    });
  }

  function collectBrandNames(value, names, inProduct) {
    if (!value || typeof value !== 'object') {
      return;
    }

    if (Array.isArray(value)) {
      value.forEach(function (entry) {
        collectBrandNames(entry, names, inProduct);
      });
      return;
    }

    var type = value['@type'];
    var types = Array.isArray(type) ? type : [type];
    var isProduct = inProduct || types.some(function (entry) {
      return normalizeText(entry) === 'product';
    });

    if (isProduct && value.brand) {
      if (typeof value.brand === 'string') {
        names.push(value.brand);
      } else if (value.brand && typeof value.brand.name === 'string') {
        names.push(value.brand.name);
      }
    }

    Object.keys(value).forEach(function (key) {
      if (key !== 'brand') {
        collectBrandNames(value[key], names, isProduct);
      }
    });
  }

  function isExpectedManufacturer(documentObject, form) {
    var evidence = [];

    Array.prototype.forEach.call(form.querySelectorAll('input'), function (input) {
      if (normalizeText(input.getAttribute('name')) === 'vyrobca' && String(input.value || '').trim()) {
        evidence.push(input.value);
      }
    });

    Array.prototype.forEach.call(form.querySelectorAll('tr'), function (row) {
      var cells = row.querySelectorAll('td');
      if (cells.length > 1 && normalizeText(cells[0].textContent).indexOf('vyrobca') === 0) {
        var visibleValue = String(cells[1].textContent || '').trim();
        if (visibleValue) {
          evidence.push(visibleValue);
        }
      }
    });

    Array.prototype.forEach.call(documentObject.querySelectorAll('script[type="application/ld+json"]'), function (script) {
      try {
        collectBrandNames(JSON.parse(script.textContent || ''), evidence, false);
      } catch (error) {
        /* Invalid unrelated JSON-LD must not break the product page. */
      }
    });

    return manufacturerEvidenceMatches(evidence);
  }

  function getExpectedSelect(form) {
    var selects = form.querySelectorAll('select[name^="ciselnik"]');
    var labelMatch = null;

    Array.prototype.some.call(selects, function (select) {
      var row = select.closest ? select.closest('tr') : null;
      var firstCell = row && row.querySelector('td');
      var label = normalizeText(firstCell && firstCell.textContent);

      if (label.indexOf('potahov') !== -1 && label.indexOf('new design') !== -1) {
        labelMatch = select;
        return true;
      }
      return false;
    });

    if (labelMatch) {
      return labelMatch;
    }

    var third = form.querySelector('select[name="ciselnik3"]');
    if (!third) {
      return null;
    }

    var containsFabric = Array.prototype.some.call(third.options || [], function (option) {
      var label = normalizeText(option.textContent || option.label || '');
      return label.indexOf('new design') !== -1 && /\b\d+\b/.test(label);
    });

    return containsFabric ? third : null;
  }

  function getLegSelect(form) {
    var selects = form.querySelectorAll('select[name^="ciselnik"]');
    var labelMatch = null;

    Array.prototype.some.call(selects, function (select) {
      var row = select.closest ? select.closest('tr') : null;
      var firstCell = row && row.querySelector('td');
      var label = normalizeText(firstCell && firstCell.textContent);

      if (label.indexOf('nozic') !== -1 || label.indexOf('nohy') !== -1) {
        labelMatch = select;
        return true;
      }
      return false;
    });

    if (labelMatch) {
      return labelMatch;
    }

    var first = form.querySelector('select[name="ciselnik1"]');
    if (!first) {
      return null;
    }

    var containsLeg = Array.prototype.some.call(first.options || [], function (option) {
      return Boolean(parseLegOptionLabel(option.textContent || option.label || ''));
    });

    return containsLeg ? first : null;
  }

  function getTopperSelect(form) {
    var selects = form.querySelectorAll('select[name^="ciselnik"]');
    var labelMatch = null;

    Array.prototype.some.call(selects, function (select) {
      var row = select.closest ? select.closest('tr') : null;
      var firstCell = row && row.querySelector('td');
      var label = normalizeText(firstCell && firstCell.textContent);

      if (label.indexOf('topper') !== -1) {
        labelMatch = select;
        return true;
      }
      return false;
    });

    if (labelMatch) {
      return labelMatch;
    }

    var second = form.querySelector('select[name="ciselnik2"]');
    if (!second) {
      return null;
    }

    try {
      buildStrictTopperMapping(second);
      return second;
    } catch (error) {
      return null;
    }
  }

  function valueCellFor(select) {
    return select && select.closest ? select.closest('td') : null;
  }

  function appendToValueArea(form, select, node) {
    var cell = valueCellFor(select);
    if (cell) {
      cell.classList.add('ndp-value-cell');

      if (node && node.classList && (
        node.classList.contains('ndp-picker') ||
        node.classList.contains('ndl-picker') ||
        node.classList.contains('ndt-picker')
      )) {
        var row = cell.closest ? cell.closest('tr') : null;
        var labelCell = row && row.querySelector ? row.querySelector('td:first-child') : null;

        if (row) {
          row.classList.add('ndp-config-row');
        }
        if (labelCell && labelCell !== cell) {
          labelCell.classList.add('ndp-config-label-cell');
        }
      }

      cell.appendChild(node);
    } else {
      form.appendChild(node);
    }
  }

  function appendFallback(documentObject, form, select, message) {
    var existing = form.querySelector('[data-ndp-fallback]');
    if (existing) {
      var existingMessage = existing.querySelector('p');
      if (existingMessage) {
        existingMessage.textContent = message;
      }
      return existing;
    }

    var box = element(documentObject, 'div', 'ndp-fallback');
    box.setAttribute('data-ndp-fallback', '');
    box.appendChild(element(documentObject, 'p', '', message));
    box.appendChild(makeCatalogLink(documentObject));

    appendToValueArea(form, select, box);
    return box;
  }

  function installPurchaseGuard(documentObject, form, nativeSelect, message) {
    var manager = form.__ndpDivaPurchaseGuardManager;

    if (!manager) {
      var requirements = [];

      function guard(event) {
        var invalid = [];

        requirements.forEach(function (requirement) {
          if (hasValidSelection(requirement.select, requirement.placeholder)) {
            requirement.clear();
          } else {
            invalid.push(requirement);
          }
        });

        if (!invalid.length) {
          return true;
        }

        event.preventDefault();
        if (typeof event.stopImmediatePropagation === 'function') {
          event.stopImmediatePropagation();
        }

        invalid.forEach(function (requirement, index) {
          requirement.show(index === 0);
        });
        return false;
      }

      manager = {
        guard: guard,
        register: function (select, errorMessage) {
          if (select.__ndpDivaPurchaseRequirement) {
            return select.__ndpDivaPurchaseRequirement;
          }

          var error = element(documentObject, 'p', 'ndp-native-error');
          var presenter = null;
          var requirement;

          error.setAttribute('role', 'alert');
          error.hidden = true;
          error.textContent = errorMessage;
          appendToValueArea(form, select, error);

          function clear() {
            error.hidden = true;
            select.removeAttribute('aria-invalid');
            if (presenter && presenter.clear) {
              presenter.clear();
            }
          }

          function show(shouldFocus) {
            select.setAttribute('aria-invalid', 'true');
            if (presenter && presenter.show) {
              presenter.show(shouldFocus);
            } else {
              error.hidden = false;
              if (shouldFocus && typeof select.focus === 'function') {
                select.focus();
              }
            }
          }

          requirement = {
            select: select,
            placeholder: findPlaceholderOption(select),
            clear: clear,
            show: show,
            guard: guard,
            setPresenter: function (nextPresenter) {
              presenter = nextPresenter;
              error.hidden = true;
            }
          };
          requirements.push(requirement);
          select.addEventListener('change', clear);
          select.__ndpDivaPurchaseRequirement = requirement;
          return requirement;
        }
      };

      form.addEventListener('submit', guard, true);
      form.addEventListener('click', function (event) {
        var target = event.target;
        var submitter = target && target.closest ? target.closest('input[type="submit"], button[type="submit"]') : target;
        if (submitter && form.contains(submitter) && submitter.matches('input[type="submit"], button[type="submit"]')) {
          guard(event);
        }
      }, true);
      form.__ndpDivaPurchaseGuardManager = manager;
    }

    return manager.register(
      nativeSelect,
      message || 'Pred pridaním do košíka vyberte poťahovú látku.'
    );
  }

  function fetchDocument(globalObject, url) {
    var PromiseConstructor = globalObject.Promise;
    var controller = typeof globalObject.AbortController === 'function' ? new globalObject.AbortController() : null;
    var timeout;
    var request = globalObject.fetch(url, {
      credentials: 'same-origin',
      headers: { Accept: 'text/html' },
      signal: controller ? controller.signal : undefined
    }).then(function (response) {
      if (!response.ok) {
        throw new Error('HTTP ' + response.status);
      }
      return response.text();
    }).then(function (html) {
      return new globalObject.DOMParser().parseFromString(html, 'text/html');
    });

    var deadline = new PromiseConstructor(function (resolve, reject) {
      timeout = globalObject.setTimeout(function () {
        if (controller) {
          controller.abort();
        }
        reject(new Error('Načítanie vzorkovníka prekročilo časový limit.'));
      }, 8000);
    });

    return PromiseConstructor.race([request, deadline]).then(function (documentObject) {
      globalObject.clearTimeout(timeout);
      return documentObject;
    }, function (error) {
      globalObject.clearTimeout(timeout);
      throw error;
    });
  }

  function loadCatalog(globalObject) {
    var index = 0;

    function tryNext() {
      if (index >= CATALOG_URLS.length) {
        return globalObject.Promise.reject(new Error('Vzorkovník nie je dostupný.'));
      }

      var url = CATALOG_URLS[index++];
      return fetchDocument(globalObject, url).then(function (documentObject) {
        return parseCatalogDocument(documentObject, globalObject.location);
      }).catch(tryNext);
    }

    return tryNext();
  }

  function createCloseIcon(documentObject) {
    var svg = documentObject.createElementNS('http://www.w3.org/2000/svg', 'svg');
    var path = documentObject.createElementNS('http://www.w3.org/2000/svg', 'path');
    svg.setAttribute('viewBox', '0 0 24 24');
    svg.setAttribute('aria-hidden', 'true');
    svg.setAttribute('focusable', 'false');
    svg.style.pointerEvents = 'none';
    path.setAttribute('d', 'M6 6l12 12M18 6L6 18');
    path.setAttribute('fill', 'none');
    path.setAttribute('stroke', 'currentColor');
    path.setAttribute('stroke-width', '2');
    path.setAttribute('stroke-linecap', 'round');
    svg.appendChild(path);
    return svg;
  }

  function applySpriteVisual(node, url, itemCount, itemIndex) {
    var position = itemCount > 1 ? (itemIndex / (itemCount - 1)) * 100 : 50;
    node.style.backgroundImage = 'url("' + url.replace(/"/g, '%22') + '")';
    node.style.backgroundSize = (itemCount * 100) + '% 100%';
    node.style.backgroundPosition = position + '% center';
    node.style.backgroundRepeat = 'no-repeat';
  }

  function findLegShape(code) {
    var found = null;
    LEG_SHAPES.some(function (shape) {
      if (shape.code === String(code)) {
        found = shape;
        return true;
      }
      return false;
    });
    return found;
  }

  function findLegFinish(key) {
    var found = null;
    LEG_FINISHES.some(function (finish) {
      if (finish.key === key) {
        found = finish;
        return true;
      }
      return false;
    });
    return found;
  }

  function topperOptionDisplay(option) {
    var text = String(option && (option.textContent || option.label) || '')
      .replace(/\u00a0/g, ' ')
      .replace(/\s+/g, ' ')
      .trim();
    var priceMatch = /\(([^()]*)\)\s*$/.exec(text);
    var label = text.replace(/\s*\([^()]*\)\s*$/, '').trim();
    var meta = priceMatch ? priceMatch[1].trim() : '';
    var titlePrice = String(option && option.getAttribute && option.getAttribute('title') || '').trim();

    if (!meta && titlePrice) {
      meta = '+' + titlePrice + ' € s DPH';
    }

    return {
      label: label,
      meta: meta || 'Bez príplatku'
    };
  }

  function enhanceTopperPicker(globalObject, form, nativeSelect, mapping, purchaseGuard) {
    var documentObject = globalObject.document;
    var placeholderOption = mapping.placeholder;
    var mount = element(documentObject, 'div', 'ndt-picker');
    var heading = numberedHeading(documentObject, 'ndt-heading', 2, 'Vyberte topper');
    var grid = element(documentObject, 'div', 'ndt-grid');
    var summary = element(documentObject, 'p', 'ndt-summary');
    var error = element(documentObject, 'p', 'ndt-error');
    var buttons = [];
    var selectedTopper = null;

    mount.setAttribute('data-ndt-enhanced', '');
    heading.id = 'ndt-heading-8162';
    grid.setAttribute('role', 'group');
    grid.setAttribute('aria-labelledby', heading.id);
    summary.setAttribute('aria-live', 'polite');
    error.id = 'ndt-error-8162';
    error.setAttribute('role', 'alert');
    error.hidden = true;
    mount.setAttribute('aria-labelledby', heading.id);
    mount.setAttribute('aria-describedby', error.id);

    TOPPER_KEYS.forEach(function (key) {
      var option = mapping.optionByKey[key];
      var copy = topperOptionDisplay(option);
      var button = element(documentObject, 'button', 'ndt-option');
      var indicator = element(documentObject, 'span', 'ndt-option__indicator');
      var text = element(documentObject, 'span', 'ndt-option__copy');
      var label = element(documentObject, 'strong', '', copy.label);
      var meta = element(documentObject, 'small', '', copy.meta);
      var check = element(documentObject, 'span', 'ndt-option__check', '✓');

      button.type = 'button';
      button.setAttribute('aria-pressed', 'false');
      button.setAttribute('aria-label', copy.label + ', ' + copy.meta);
      button.setAttribute('data-ndt-option', key);
      indicator.setAttribute('aria-hidden', 'true');
      check.setAttribute('aria-hidden', 'true');
      text.appendChild(label);
      text.appendChild(meta);
      button.appendChild(indicator);
      button.appendChild(text);
      button.appendChild(check);
      grid.appendChild(button);
      buttons.push({ button: button, key: key, option: option, copy: copy });
    });

    mount.appendChild(heading);
    mount.appendChild(grid);
    mount.appendChild(summary);
    mount.appendChild(error);
    appendToValueArea(form, nativeSelect, mount);

    function getSelectedOption() {
      return nativeSelect.selectedIndex >= 0 ? nativeSelect.options[nativeSelect.selectedIndex] : null;
    }

    function clearValidation() {
      error.hidden = true;
      error.textContent = '';
      mount.classList.remove('is-invalid');
    }

    function showValidation(shouldFocus) {
      error.textContent = 'Pred pridaním do košíka vyberte topper alebo možnosť bez toppera.';
      error.hidden = false;
      mount.classList.add('is-invalid');
      if (shouldFocus && buttons.length) {
        buttons[0].button.focus();
      }
    }

    function syncFromNative() {
      var option = getSelectedOption();
      selectedTopper = hasValidSelection(nativeSelect, placeholderOption) && option ?
        mapping.topperByValue[String(option.value)] || null : null;

      buttons.forEach(function (entry) {
        entry.button.setAttribute('aria-pressed', String(Boolean(selectedTopper && selectedTopper.key === entry.key)));
      });

      if (selectedTopper) {
        var selectedEntry = null;
        buttons.some(function (entry) {
          if (entry.key === selectedTopper.key) {
            selectedEntry = entry;
            return true;
          }
          return false;
        });
        summary.textContent = selectedEntry ?
          'Vybrané: ' + selectedEntry.copy.label + ' · ' + selectedEntry.copy.meta :
          'Topper je vybraný.';
      } else {
        summary.textContent = 'Vyberte jednu z možností.';
      }
    }

    buttons.forEach(function (entry) {
      entry.button.addEventListener('click', function () {
        nativeSelect.value = entry.option.value;
        dispatchNativeEvent(globalObject, nativeSelect, 'input');
        dispatchNativeEvent(globalObject, nativeSelect, 'change');
        clearValidation();
        syncFromNative();
      });
    });

    nativeSelect.addEventListener('change', function () {
      clearValidation();
      syncFromNative();
    });
    purchaseGuard.setPresenter({ show: showValidation, clear: clearValidation });

    nativeSelect.classList.add('ndp-native-select--enhanced');
    nativeSelect.setAttribute('aria-hidden', 'true');
    nativeSelect.setAttribute('tabindex', '-1');
    syncFromNative();
  }

  function enhanceLegPicker(globalObject, form, nativeSelect, mapping, purchaseGuard) {
    var documentObject = globalObject.document;
    var placeholderOption = mapping.placeholder;
    var mount = element(documentObject, 'div', 'ndl-picker');
    var heading = numberedHeading(documentObject, 'ndl-heading', 1, 'Vyberte nožičky');
    var shapeGroup = element(documentObject, 'div', 'ndl-group ndl-group--shape');
    var shapeHeading = element(documentObject, 'p', 'ndl-step-title', 'Tvar nožičky');
    var shapeGrid = element(documentObject, 'div', 'ndl-shape-grid');
    var finishGroup = element(documentObject, 'div', 'ndl-group ndl-group--finish');
    var finishHeading = element(documentObject, 'p', 'ndl-step-title', 'Farba a morenie');
    var finishGrid = element(documentObject, 'div', 'ndl-finish-grid');
    var finishHint = element(documentObject, 'p', 'ndl-finish-hint', 'Chróm je dostupný iba pre nohu č. 2 a č. 4.');
    var summary = element(documentObject, 'p', 'ndl-summary');
    var error = element(documentObject, 'p', 'ndl-error');
    var shapeButtons = [];
    var finishButtons = [];
    var selectedLeg = null;
    var pendingShape = null;

    mount.setAttribute('data-ndl-enhanced', '');
    heading.id = 'ndl-heading-8162';
    shapeHeading.id = 'ndl-shape-heading-8162';
    finishHeading.id = 'ndl-finish-heading-8162';
    shapeGroup.setAttribute('role', 'group');
    shapeGroup.setAttribute('aria-labelledby', shapeHeading.id);
    finishGroup.setAttribute('role', 'group');
    finishGroup.setAttribute('aria-labelledby', finishHeading.id);
    summary.setAttribute('aria-live', 'polite');
    error.id = 'ndl-error-8162';
    error.setAttribute('role', 'alert');
    error.hidden = true;
    mount.setAttribute('aria-labelledby', heading.id);
    mount.setAttribute('aria-describedby', error.id);

    LEG_SHAPES.forEach(function (shape, index) {
      var button = element(documentObject, 'button', 'ndl-shape');
      var visual = element(documentObject, 'span', 'ndl-shape__visual');
      var copy = element(documentObject, 'span', 'ndl-shape__copy');
      var name = element(documentObject, 'strong', '', shape.label);
      var height = element(documentObject, 'small', '', 'Výška ' + shape.height);

      button.type = 'button';
      button.setAttribute('aria-pressed', 'false');
      button.setAttribute('aria-label', 'Vybrať ' + shape.label.toLowerCase() + ', výška ' + shape.height);
      visual.setAttribute('aria-hidden', 'true');
      applySpriteVisual(visual, LEG_SHAPE_SPRITE_URL, LEG_SHAPES.length, index);
      copy.appendChild(name);
      copy.appendChild(height);
      button.appendChild(visual);
      button.appendChild(copy);
      shapeGrid.appendChild(button);
      shapeButtons.push({ button: button, shape: shape });
    });

    LEG_FINISHES.forEach(function (finish, index) {
      var button = element(documentObject, 'button', 'ndl-finish');
      var visual = element(documentObject, 'span', 'ndl-finish__visual');
      var label = element(documentObject, 'span', 'ndl-finish__label', finish.label);

      button.type = 'button';
      button.setAttribute('aria-pressed', 'false');
      button.setAttribute('aria-label', 'Vybrať povrch ' + finish.label.toLowerCase());
      visual.setAttribute('aria-hidden', 'true');
      applySpriteVisual(visual, LEG_FINISH_SPRITE_URL, LEG_FINISHES.length, index);
      button.appendChild(visual);
      button.appendChild(label);
      finishGrid.appendChild(button);
      finishButtons.push({ button: button, finish: finish });
    });

    shapeGroup.appendChild(shapeHeading);
    shapeGroup.appendChild(shapeGrid);
    finishGroup.appendChild(finishHeading);
    finishGroup.appendChild(finishGrid);
    finishGroup.appendChild(finishHint);
    mount.appendChild(heading);
    mount.appendChild(shapeGroup);
    mount.appendChild(finishGroup);
    mount.appendChild(summary);
    mount.appendChild(error);
    appendToValueArea(form, nativeSelect, mount);

    function getSelectedOption() {
      return nativeSelect.selectedIndex >= 0 ? nativeSelect.options[nativeSelect.selectedIndex] : null;
    }

    function clearValidation() {
      error.hidden = true;
      error.textContent = '';
      mount.classList.remove('is-invalid');
    }

    function showValidation(shouldFocus) {
      error.textContent = pendingShape ?
        'Dokončite výber povrchu nožičiek.' :
        'Pred pridaním do košíka vyberte nožičky.';
      error.hidden = false;
      mount.classList.add('is-invalid');

      if (shouldFocus) {
        if (pendingShape) {
          var firstAvailableFinish = null;
          finishButtons.some(function (entry) {
            if (!entry.button.disabled) {
              firstAvailableFinish = entry.button;
              return true;
            }
            return false;
          });
          if (firstAvailableFinish) {
            firstAvailableFinish.focus();
          }
        } else if (shapeButtons.length) {
          shapeButtons[0].button.focus();
        }
      }
    }

    function updateInterface() {
      var selectedShape = selectedLeg && findLegShape(selectedLeg.shape);
      var selectedFinish = selectedLeg && findLegFinish(selectedLeg.finish);
      var pendingShapeDefinition = pendingShape && findLegShape(pendingShape);

      shapeButtons.forEach(function (entry) {
        entry.button.setAttribute('aria-pressed', String(entry.shape.code === pendingShape));
      });

      finishButtons.forEach(function (entry) {
        var available = Boolean(pendingShape) &&
          (!entry.finish.chrome || pendingShape === '2' || pendingShape === '4');
        var pressed = Boolean(
          selectedLeg &&
          selectedLeg.shape === pendingShape &&
          selectedLeg.finish === entry.finish.key
        );
        entry.button.disabled = !available;
        entry.button.setAttribute('aria-pressed', String(pressed));
      });

      if (selectedLeg && selectedShape && selectedFinish) {
        summary.textContent = 'Vybrané: ' + selectedShape.label + ' · ' + selectedFinish.label + ' · výška ' + selectedShape.height;
      } else if (pendingShapeDefinition) {
        summary.textContent = 'Vybrali ste ' + pendingShapeDefinition.label.toLowerCase() + '. Teraz zvoľte farbu alebo morenie.';
      } else {
        summary.textContent = 'Najprv vyberte tvar nožičky.';
      }
    }

    function syncFromNative(preservePendingShape) {
      var option = getSelectedOption();
      selectedLeg = hasValidSelection(nativeSelect, placeholderOption) && option ?
        mapping.legByValue[String(option.value)] || null : null;

      if (selectedLeg) {
        pendingShape = selectedLeg.shape;
      } else if (!preservePendingShape) {
        pendingShape = null;
      }
      updateInterface();
    }

    shapeButtons.forEach(function (entry) {
      entry.button.addEventListener('click', function () {
        var changingShape = selectedLeg && selectedLeg.shape !== entry.shape.code;
        pendingShape = entry.shape.code;

        if (changingShape) {
          nativeSelect.value = placeholderOption.value;
          dispatchNativeEvent(globalObject, nativeSelect, 'input');
          dispatchNativeEvent(globalObject, nativeSelect, 'change');
          selectedLeg = null;
          pendingShape = entry.shape.code;
        }

        clearValidation();
        updateInterface();
      });
    });

    finishButtons.forEach(function (entry) {
      entry.button.addEventListener('click', function () {
        if (!pendingShape) {
          showValidation(true);
          return;
        }

        var option = mapping.optionByKey[legCombinationKey(pendingShape, entry.finish.key)] || null;
        if (!option || entry.button.disabled) {
          return;
        }

        nativeSelect.value = option.value;
        dispatchNativeEvent(globalObject, nativeSelect, 'input');
        dispatchNativeEvent(globalObject, nativeSelect, 'change');
        clearValidation();
        syncFromNative(true);
      });
    });

    nativeSelect.addEventListener('change', function () {
      clearValidation();
      syncFromNative(true);
    });
    purchaseGuard.setPresenter({ show: showValidation, clear: clearValidation });

    nativeSelect.classList.add('ndp-native-select--enhanced');
    nativeSelect.setAttribute('aria-hidden', 'true');
    nativeSelect.setAttribute('tabindex', '-1');
    syncFromNative(false);
  }

  function enhance(globalObject, form, nativeSelect, fabrics, mapping, purchaseGuard) {
    var documentObject = globalObject.document;
    var placeholderOption = mapping.placeholder;
    var mount = element(documentObject, 'div', 'ndp-picker');
    var heading = numberedHeading(documentObject, 'ndp-heading', 3, 'Vyberte látku');
    var trigger = element(documentObject, 'button', 'ndp-trigger');
    var triggerVisual = element(documentObject, 'span', 'ndp-trigger__visual');
    var triggerCopy = element(documentObject, 'span', 'ndp-trigger__copy');
    var triggerEyebrow = element(documentObject, 'small', 'ndp-trigger__eyebrow', 'Poťah zatiaľ nie je vybraný');
    var triggerTitle = element(documentObject, 'strong', '', 'Vybrať zo vzorkovníka New Design');
    var triggerMeta = element(documentObject, 'span', 'ndp-trigger__meta', fabrics.length + ' vzoriek · New Design');
    var triggerAction = element(documentObject, 'span', 'ndp-trigger__action');
    var triggerArrow = element(documentObject, 'b', '', '→');
    var error = element(documentObject, 'p', 'ndp-error');
    var selectedFabric = null;
    var activeFabric = null;
    var previousFocus = null;
    var inertedNodes = [];

    trigger.type = 'button';
    trigger.setAttribute('aria-haspopup', 'dialog');
    trigger.setAttribute('aria-controls', 'ndp-fabric-dialog-8162');
    trigger.setAttribute('aria-expanded', 'false');
    triggerVisual.setAttribute('aria-hidden', 'true');
    triggerVisual.textContent = '+';
    triggerAction.setAttribute('aria-hidden', 'true');
    triggerAction.appendChild(documentObject.createTextNode('Vybrať látku '));
    triggerAction.appendChild(triggerArrow);
    triggerCopy.appendChild(triggerEyebrow);
    triggerCopy.appendChild(triggerTitle);
    triggerCopy.appendChild(triggerMeta);
    trigger.appendChild(triggerVisual);
    trigger.appendChild(triggerCopy);
    trigger.appendChild(triggerAction);

    error.id = 'ndp-fabric-error-8162';
    error.setAttribute('role', 'alert');
    error.hidden = true;
    trigger.setAttribute('aria-describedby', error.id);

    mount.appendChild(heading);
    mount.appendChild(trigger);
    mount.appendChild(error);
    appendToValueArea(form, nativeSelect, mount);

    var overlay = element(documentObject, 'div', 'ndp-modal');
    var dialog = element(documentObject, 'section', 'ndp-modal__dialog');
    var header = element(documentObject, 'header', 'ndp-modal__header');
    var headingGroup = element(documentObject, 'div', 'ndp-modal__heading');
    var eyebrow = element(documentObject, 'span', 'ndp-eyebrow', 'NEW DESIGN');
    var heading = element(documentObject, 'h2', '', 'Vyberte poťahovú látku');
    var closeButton = element(documentObject, 'button', 'ndp-close');
    var body = element(documentObject, 'div', 'ndp-modal__body');
    var searchLabel = element(documentObject, 'label', 'ndp-search-label', 'Hľadať látku');
    var search = element(documentObject, 'input', 'ndp-search');
    var count = element(documentObject, 'p', 'ndp-count');
    var content = element(documentObject, 'div', 'ndp-content');
    var listWrap = element(documentObject, 'div', 'ndp-list-wrap');
    var list = element(documentObject, 'ul', 'ndp-list');
    var empty = element(documentObject, 'p', 'ndp-empty', 'Pre zadaný výraz sa nenašla žiadna látka.');
    var preview = element(documentObject, 'aside', 'ndp-preview');
    var previewEmpty = element(documentObject, 'p', 'ndp-preview__empty', 'Kliknite na vzorku a tu sa zobrazí jej veľký detail.');
    var previewImage = element(documentObject, 'img', 'ndp-preview__image');
    var previewName = element(documentObject, 'strong', 'ndp-preview__name');
    var previewNote = element(documentObject, 'p', 'ndp-preview__note', 'Odtieň na obrazovke sa môže mierne líšiť od skutočnej látky.');
    var chooseButton = element(documentObject, 'button', 'ndp-choose', 'Vybrať túto látku');
    var previewError = element(documentObject, 'p', 'ndp-preview__error');
    var cards = [];

    overlay.id = 'ndp-fabric-dialog-8162';
    overlay.hidden = true;
    dialog.setAttribute('role', 'dialog');
    dialog.setAttribute('aria-modal', 'true');
    dialog.setAttribute('aria-labelledby', 'ndp-fabric-title-8162');
    dialog.setAttribute('tabindex', '-1');
    heading.id = 'ndp-fabric-title-8162';
    headingGroup.appendChild(eyebrow);
    headingGroup.appendChild(heading);
    closeButton.type = 'button';
    closeButton.setAttribute('aria-label', 'Zavrieť výber látky');
    closeButton.appendChild(createCloseIcon(documentObject));
    header.appendChild(headingGroup);
    header.appendChild(closeButton);

    search.type = 'search';
    search.placeholder = 'Názov alebo číslo látky';
    search.autocomplete = 'off';
    searchLabel.appendChild(search);
    count.setAttribute('aria-live', 'polite');
    empty.hidden = true;
    listWrap.appendChild(list);
    listWrap.appendChild(empty);

    previewImage.alt = '';
    previewImage.hidden = true;
    previewName.hidden = true;
    previewNote.hidden = true;
    chooseButton.type = 'button';
    chooseButton.disabled = true;
    previewError.setAttribute('role', 'status');
    previewError.hidden = true;
    preview.appendChild(previewEmpty);
    preview.appendChild(previewImage);
    preview.appendChild(previewName);
    preview.appendChild(previewNote);
    preview.appendChild(chooseButton);
    preview.appendChild(previewError);
    content.appendChild(listWrap);
    content.appendChild(preview);
    body.appendChild(searchLabel);
    body.appendChild(count);
    body.appendChild(content);
    dialog.appendChild(header);
    dialog.appendChild(body);
    overlay.appendChild(dialog);
    documentObject.body.appendChild(overlay);

    function getSelectedOption() {
      return nativeSelect.selectedIndex >= 0 ? nativeSelect.options[nativeSelect.selectedIndex] : null;
    }

    function clearValidation() {
      error.hidden = true;
      error.textContent = '';
      trigger.removeAttribute('aria-invalid');
    }

    function showValidation(shouldFocus) {
      error.textContent = 'Pred pridaním do košíka vyberte poťahovú látku.';
      error.hidden = false;
      trigger.setAttribute('aria-invalid', 'true');
      if (shouldFocus) {
        trigger.focus();
      }
    }

    function updateTrigger() {
      var option = getSelectedOption();
      selectedFabric = hasValidSelection(nativeSelect, placeholderOption) && option ? mapping.fabricByValue[String(option.value)] || null : null;
      triggerVisual.textContent = '+';
      triggerVisual.style.backgroundImage = '';
      triggerVisual.classList.remove('has-image');

      if (selectedFabric) {
        triggerVisual.textContent = '';
        triggerVisual.style.backgroundImage = 'url("' + selectedFabric.hybrid.replace(/"/g, '%22') + '")';
        triggerVisual.classList.add('has-image');
        triggerEyebrow.textContent = 'Poťah je vybraný';
        triggerTitle.textContent = selectedFabric.name;
        triggerMeta.textContent = 'Poťah je pripravený pre košík';
      } else if (hasValidSelection(nativeSelect, placeholderOption) && option) {
        triggerEyebrow.textContent = 'Systémová voľba';
        triggerTitle.textContent = String(option.textContent || option.label || '').replace(/\s+/g, ' ').trim();
        triggerMeta.textContent = 'Systémová voľba Webarealu';
      } else {
        triggerEyebrow.textContent = 'Poťah zatiaľ nie je vybraný';
        triggerTitle.textContent = 'Vybrať zo vzorkovníka New Design';
        triggerMeta.textContent = fabrics.length + ' vzoriek · New Design';
      }

      cards.forEach(function (entry) {
        entry.button.setAttribute('aria-pressed', String(Boolean(selectedFabric && selectedFabric.code === entry.fabric.code)));
      });
    }

    function showPreview(fabric) {
      activeFabric = fabric;
      previewEmpty.hidden = true;
      previewImage.hidden = false;
      previewName.hidden = false;
      previewNote.hidden = false;
      previewImage.src = fabric.large;
      previewImage.alt = 'Veľký náhľad poťahovej látky ' + fabric.name;
      previewName.textContent = fabric.name;
      previewError.hidden = true;
      previewError.textContent = '';

      var option = mapping.optionByCode[normalizeText(fabric.code)] || null;
      chooseButton.disabled = !option;
      if (!option) {
        previewError.textContent = 'Táto látka zatiaľ nie je v systémovom číselníku produktu a nemožno ju vložiť do košíka.';
        previewError.hidden = false;
      }

      cards.forEach(function (entry) {
        entry.button.classList.toggle('is-previewed', entry.fabric.code === fabric.code);
      });

      if (globalObject.matchMedia && globalObject.matchMedia('(max-width: 720px)').matches) {
        var reduceMotion = globalObject.matchMedia('(prefers-reduced-motion: reduce)').matches;
        preview.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'nearest' });
      }
    }

    fabrics.forEach(function (fabric) {
      var item = element(documentObject, 'li', 'ndp-card-item');
      var button = element(documentObject, 'button', 'ndp-card');
      var image = element(documentObject, 'img', 'ndp-card__image');
      var name = element(documentObject, 'strong', '', fabric.name);
      button.type = 'button';
      button.setAttribute('aria-pressed', 'false');
      button.setAttribute('aria-label', 'Zobraziť detail látky ' + fabric.name);
      image.src = fabric.hybrid;
      image.alt = '';
      image.loading = 'lazy';
      image.decoding = 'async';
      button.appendChild(image);
      button.appendChild(name);
      button.addEventListener('click', function () {
        showPreview(fabric);
      });
      item.appendChild(button);
      list.appendChild(item);
      cards.push({ item: item, button: button, fabric: fabric, search: normalizeText(fabric.name + ' ' + fabric.code) });
    });

    function filterCards() {
      var query = normalizeText(search.value);
      var visible = 0;
      cards.forEach(function (entry) {
        var show = !query || entry.search.indexOf(query) !== -1;
        entry.item.hidden = !show;
        if (show) {
          visible += 1;
        }
      });
      count.textContent = visible + ' ' + (visible === 1 ? 'vzorka' : (visible > 1 && visible < 5 ? 'vzorky' : 'vzoriek')) + ' · New Design';
      empty.hidden = visible !== 0;
    }

    function openDialog() {
      previousFocus = documentObject.activeElement;
      activeFabric = selectedFabric;
      overlay.hidden = false;
      trigger.setAttribute('aria-expanded', 'true');
      inertedNodes = [];
      Array.prototype.forEach.call(documentObject.body.children, function (node) {
        if (node !== overlay && 'inert' in node) {
          inertedNodes.push({ node: node, value: node.inert });
          node.inert = true;
        }
      });
      documentObject.body.classList.add('ndp-modal-open');
      body.scrollTop = 0;
      list.scrollTop = 0;
      search.value = '';
      filterCards();
      if (activeFabric) {
        showPreview(activeFabric);
      } else {
        previewEmpty.hidden = false;
        previewImage.hidden = true;
        previewName.hidden = true;
        previewNote.hidden = true;
        chooseButton.disabled = true;
        previewError.hidden = true;
      }
      globalObject.setTimeout(function () {
        search.focus();
      }, 0);
    }

    function closeDialog() {
      overlay.hidden = true;
      trigger.setAttribute('aria-expanded', 'false');
      documentObject.body.classList.remove('ndp-modal-open');
      previewImage.removeAttribute('src');
      inertedNodes.forEach(function (entry) {
        entry.node.inert = entry.value;
      });
      inertedNodes = [];
      if (previousFocus && typeof previousFocus.focus === 'function') {
        previousFocus.focus();
      }
    }

    function focusableNodes() {
      return Array.prototype.filter.call(
        dialog.querySelectorAll('button:not([disabled]), input:not([disabled]), a[href]'),
        function (node) { return !node.hidden && node.offsetParent !== null; }
      );
    }

    function trapFocus(event) {
      if (event.key === 'Escape') {
        event.preventDefault();
        closeDialog();
        return;
      }

      if (event.key !== 'Tab') {
        return;
      }

      var nodes = focusableNodes();
      if (!nodes.length) {
        event.preventDefault();
        dialog.focus();
        return;
      }

      var first = nodes[0];
      var last = nodes[nodes.length - 1];
      if (event.shiftKey && documentObject.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && documentObject.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    }

    function chooseActiveFabric() {
      if (!activeFabric) {
        return;
      }

      var option = mapping.optionByCode[normalizeText(activeFabric.code)] || null;
      if (!option) {
        previewError.hidden = false;
        return;
      }

      nativeSelect.value = option.value;
      dispatchNativeEvent(globalObject, nativeSelect, 'input');
      dispatchNativeEvent(globalObject, nativeSelect, 'change');
      clearValidation();
      updateTrigger();
      closeDialog();
    }

    trigger.addEventListener('click', openDialog);
    closeButton.addEventListener('click', closeDialog);
    chooseButton.addEventListener('click', chooseActiveFabric);
    search.addEventListener('input', filterCards);
    dialog.addEventListener('keydown', trapFocus);
    documentObject.addEventListener('keydown', function (event) {
      if (overlay.hidden || event.key !== 'Escape') {
        return;
      }
      event.preventDefault();
      event.stopPropagation();
      closeDialog();
    }, true);
    overlay.addEventListener('click', function (event) {
      if (event.target === overlay) {
        closeDialog();
      }
    });
    nativeSelect.addEventListener('change', function () {
      clearValidation();
      updateTrigger();
    });
    purchaseGuard.setPresenter({ show: showValidation, clear: clearValidation });

    nativeSelect.classList.add('ndp-native-select--enhanced');
    nativeSelect.setAttribute('aria-hidden', 'true');
    nativeSelect.setAttribute('tabindex', '-1');
    mount.setAttribute('data-ndp-enhanced', '');
    updateTrigger();
    filterCards();
  }

  function boot(globalObject) {
    var documentObject = globalObject.document;

    function start() {
      var body = documentObject.body;
      if (!body || !body.classList.contains('page-product-8162')) {
        return;
      }

      var form = getProductForm(documentObject);
      if (!form) {
        return;
      }

      if (!isExpectedManufacturer(documentObject, form)) {
        return;
      }

      var legSelect = getLegSelect(form);
      if (legSelect) {
        var legPurchaseGuard = installPurchaseGuard(
          documentObject,
          form,
          legSelect,
          'Pred pridaním do košíka vyberte nožičky.'
        );

        if (!body.querySelector('[data-ndl-enhanced]')) {
          try {
            enhanceLegPicker(
              globalObject,
              form,
              legSelect,
              buildStrictLegMapping(legSelect),
              legPurchaseGuard
            );
          } catch (error) {
            /* Pri neúplnom číselníku zostáva bezpečne viditeľný natívny select. */
          }
        }
      }

      var topperSelect = getTopperSelect(form);
      if (topperSelect) {
        var topperPurchaseGuard = installPurchaseGuard(
          documentObject,
          form,
          topperSelect,
          'Pred pridaním do košíka vyberte topper alebo možnosť bez toppera.'
        );

        if (!body.querySelector('[data-ndt-enhanced]')) {
          try {
            enhanceTopperPicker(
              globalObject,
              form,
              topperSelect,
              buildStrictTopperMapping(topperSelect),
              topperPurchaseGuard
            );
          } catch (error) {
            /* Pri neúplnom číselníku zostáva bezpečne viditeľný natívny select. */
          }
        }
      }

      var nativeSelect = getExpectedSelect(form);
      if (!nativeSelect) {
        appendFallback(
          documentObject,
          form,
          null,
          'Vzorkovník je dostupný, ale systémové pole „Výber poťahu – New Design“ zatiaľ nie je pripojené k tomuto produktu.'
        );
        return;
      }

      var purchaseGuard = installPurchaseGuard(documentObject, form, nativeSelect);
      if (body.querySelector('[data-ndp-enhanced]')) {
        return;
      }
      if (typeof globalObject.Promise !== 'function' ||
          typeof globalObject.fetch !== 'function' ||
          typeof globalObject.DOMParser !== 'function') {
        appendFallback(
          documentObject,
          form,
          nativeSelect,
          'Prehliadač nepodporuje vizuálny vzorkovník. Látku vyberte v systémovom poli.'
        );
        return;
      }

      if (body.getAttribute('data-ndp-loading') === 'true') {
        return;
      }

      body.setAttribute('data-ndp-loading', 'true');
      loadCatalog(globalObject).then(function (fabrics) {
        var mapping = buildStrictMapping(nativeSelect, fabrics);
        var fallback = form.querySelector('[data-ndp-fallback]');
        if (fallback && fallback.parentNode) {
          fallback.parentNode.removeChild(fallback);
        }
        if (!body.querySelector('[data-ndp-enhanced]')) {
          enhance(globalObject, form, nativeSelect, fabrics, mapping, purchaseGuard);
        }
        body.removeAttribute('data-ndp-loading');
      }).catch(function () {
        body.removeAttribute('data-ndp-loading');
        appendFallback(
          documentObject,
          form,
          nativeSelect,
          'Vizuálny vzorkovník sa nepodarilo načítať. Látku vyberte v systémovom poli.'
        );
      });
    }

    if (documentObject.readyState === 'loading') {
      documentObject.addEventListener('DOMContentLoaded', start, { once: true });
    } else {
      start();
    }
  }

  return {
    PRODUCT_ID: PRODUCT_ID,
    EXPECTED_MAKER: EXPECTED_MAKER,
    EXPECTED_FABRIC_COUNT: EXPECTED_FABRIC_COUNT,
    CATALOG_URLS: CATALOG_URLS.slice(),
    LEG_SHAPE_SPRITE_URL: LEG_SHAPE_SPRITE_URL,
    LEG_FINISH_SPRITE_URL: LEG_FINISH_SPRITE_URL,
    LEG_SHAPES: LEG_SHAPES.slice(),
    LEG_FINISHES: LEG_FINISHES.slice(),
    TOPPER_KEYS: TOPPER_KEYS.slice(),
    normalizeText: normalizeText,
    legCombinationKey: legCombinationKey,
    parseLegOptionLabel: parseLegOptionLabel,
    parseTopperOptionLabel: parseTopperOptionLabel,
    isPlaceholderText: isPlaceholderText,
    scoreOptionLabel: scoreOptionLabel,
    findOptionForFabric: findOptionForFabric,
    findFabricForOption: findFabricForOption,
    findPlaceholderOption: findPlaceholderOption,
    hasValidSelection: hasValidSelection,
    manufacturerEvidenceMatches: manufacturerEvidenceMatches,
    validateCatalogFabrics: validateCatalogFabrics,
    buildStrictMapping: buildStrictMapping,
    expectedLegCombinationKeys: expectedLegCombinationKeys,
    buildStrictLegMapping: buildStrictLegMapping,
    buildStrictTopperMapping: buildStrictTopperMapping,
    parseCatalogDocument: parseCatalogDocument,
    boot: boot
  };
});
