{"id":963,"date":"2026-07-02T08:19:40","date_gmt":"2026-07-02T08:19:40","guid":{"rendered":"https:\/\/elecrest.dreamhosters.com\/?page_id=963"},"modified":"2026-09-04T09:52:11","modified_gmt":"2026-09-04T07:52:11","slug":"configurator","status":"publish","type":"page","link":"https:\/\/elecrest.energy\/fr\/configurator\/","title":{"rendered":"Configurator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"963\" class=\"elementor elementor-963\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d8267bb e-flex e-con-boxed e-con e-parent\" data-id=\"d8267bb\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a73e7df elementor-widget__width-initial elementor-widget elementor-widget-html\" data-id=\"a73e7df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<script>\r\n(function () {\r\n  \"use strict\";\r\n\r\n  var COMPONENT_SELECTOR = \"[data-ec-configurator]\";\r\n\r\n  function initialiseConfigurator(root) {\r\n    if (!root || root.getAttribute(\"data-ec-ready\") === \"true\") return;\r\n    root.setAttribute(\"data-ec-ready\", \"true\");\r\n\r\n    \/* Central asset configuration for the selection screen and configurator canvas. *\/\r\n    var SETTINGS = {\r\n      assetsBaseUrl: \"https:\/\/elecrest.energy\/wp-content\/uploads\/2026\/07\/\",\r\n      backgroundImageUrl: \"\",\r\n      selectionHoverBackgroundImageUrl: \"https:\/\/elecrest.energy\/wp-content\/uploads\/2026\/09\/configurator-page-half-size-background-scaled.webp\",\r\n      contactPopupId: 452\r\n    };\r\n\r\n    var ASSETS = {\r\n      \"240kW\": {\r\n        baseNormal: SETTINGS.assetsBaseUrl + \"hyc-240-base-normal.webp\",\r\n        baseAccessible: SETTINGS.assetsBaseUrl + \"hyc-240-base-accessible.webp\",\r\n        baseNormalPos: SETTINGS.assetsBaseUrl + \"hyc-240-base-normal-pos.webp\",\r\n        baseAccessiblePos: SETTINGS.assetsBaseUrl + \"hyc-240-base-accessible-pos.webp\",\r\n        colourBase: SETTINGS.assetsBaseUrl + \"hyc-240-color-base.webp\",\r\n        maskBody: SETTINGS.assetsBaseUrl + \"hyc-240-mask-body.webp\",\r\n        maskStripe: SETTINGS.assetsBaseUrl + \"hyc-240-mask-stripe.webp\",\r\n        power1: SETTINGS.assetsBaseUrl + \"hyc-240-power-1.webp\",\r\n        power2: SETTINGS.assetsBaseUrl + \"hyc-240-power-2.webp\",\r\n        powerEmpty: SETTINGS.assetsBaseUrl + \"hyc-240-power-empty.webp\"\r\n      },\r\n      \"480kW\": {\r\n        baseNormal: SETTINGS.assetsBaseUrl + \"hyc-480-base-normal.webp\",\r\n        baseAccessible: SETTINGS.assetsBaseUrl + \"hyc-480-base-accessible.webp\",\r\n        baseNormalPos: SETTINGS.assetsBaseUrl + \"hyc-480-base-normal-pos.webp\",\r\n        baseAccessiblePos: SETTINGS.assetsBaseUrl + \"hyc-480-base-accessible-pos.webp\",\r\n        colourBase: SETTINGS.assetsBaseUrl + \"hyc-480-color-base.webp\",\r\n        maskBody: SETTINGS.assetsBaseUrl + \"hyc-480-mask-body.webp\",\r\n        maskStripe: SETTINGS.assetsBaseUrl + \"hyc-480-mask-stripe.webp\",\r\n        power3: SETTINGS.assetsBaseUrl + \"hyc-240-power-3.webp\",\r\n        power4: SETTINGS.assetsBaseUrl + \"hyc-240-power-4.webp\",\r\n        powerEmpty: SETTINGS.assetsBaseUrl + \"hyc-480-power-empty.webp\"\r\n      }\r\n    };\r\n\r\n    var MODEL_DATA = {\r\n      \"240kW\": {\r\n        name: \"HIMA 240\",\r\n        powers: [\r\n          { value: \"1\", output: \"120 kW\", modules: \"1 Module\", imageKey: \"power1\" },\r\n          { value: \"2\", output: \"240 kW\", modules: \"2 Modules\", imageKey: \"power2\" }\r\n        ],\r\n        connectorPositions: [1, 2]\r\n      },\r\n      \"480kW\": {\r\n        name: \"HIMA 480\",\r\n        powers: [\r\n          { value: \"3\", output: \"360 kW\", modules: \"3 Modules\", imageKey: \"power3\" },\r\n          { value: \"4\", output: \"480 kW\", modules: \"4 Modules\", imageKey: \"power4\" }\r\n        ],\r\n        connectorPositions: [1, 2, 3, 4]\r\n      }\r\n    };\r\n\r\n    var CONNECTOR_TYPES = [\"CCS2\", \"CHAdeMO\", \"GB\", \"Type2\"];\r\n\r\n    var SUMMARY_SLIDES = [\r\n      { layer: \"closed\", label: \"Initial Product\" },\r\n      { layer: \"power\", label: \"Power Modules\" },\r\n      { layer: \"closed\", label: \"Configuration\" },\r\n      { layer: \"colour\", label: \"Final Colour\" }\r\n    ];\r\n\r\n    \/* Reference specification carried forward from the approved legacy configurator. *\/\r\n    var PARAMETER_TABLES = {\r\n      \"240kW\": {\r\n        variants: [\"120 kW\", \"240 kW\"],\r\n        rows: [\r\n          { section: \"Input\", item: \"Rated Voltage\", values: [\"400 Vac +\/-10%\", \"400 Vac +\/-10%\"] },\r\n          { section: \"\", item: \"Rated Current\", values: [\"180 A\", \"360 A\"] },\r\n          { section: \"Output\", item: \"Power\", values: [\"120 kW\", \"240 kW\"] },\r\n          { section: \"\", item: \"Connector Type (Optional)\", values: [\"CCS2 x2\", \"CCS2 x2\"] },\r\n          { section: \"\", item: \"Voltage\", values: [\"150-1000 Vdc\", \"150-1000 Vdc\"] },\r\n          { section: \"\", item: \"Current\", values: [\"250 A\", \"250 A\"] },\r\n          { section: \"\", item: \"Efficiency\", values: [\">=97%\", \">=97%\"] },\r\n          { section: \"\", item: \"Connector Quantity\", values: [\"Optional, max. 2\", \"Optional, max. 2\"] },\r\n          { section: \"Interaction\", item: \"Status LED\", values: [\"Per connector\", \"Per connector\"] },\r\n          { section: \"\", item: \"Meter\", values: [\"MID\", \"MID\"] },\r\n          { section: \"\", item: \"Activation Method\", values: [\"RFID \/ App \/ POS\", \"RFID \/ App \/ POS\"] },\r\n          { section: \"\", item: \"Network\", values: [\"Ethernet; 4G\", \"Ethernet; 4G\"] },\r\n          { section: \"\", item: \"Screen\", values: [\"10-inch screen, 4 buttons\", \"10-inch screen, 4 buttons\"] },\r\n          { section: \"\", item: \"Language\", values: [\"English (optional)\", \"English (optional)\"] },\r\n          { section: \"\", item: \"POS\", values: [\"Optional\", \"Optional\"] },\r\n          { section: \"\", item: \"Protocol\", values: [\"OCPP 1.6J\", \"OCPP 1.6J\"] },\r\n          { section: \"Operating Conditions\", item: \"Operating Temperature\", values: [\"-30 C to 55 C\", \"-30 C to 55 C\"] },\r\n          { section: \"\", item: \"Storage Temperature\", values: [\"-30 C to 70 C\", \"-30 C to 70 C\"] },\r\n          { section: \"\", item: \"Relative Humidity\", values: [\"5%-95%, non-condensing\", \"5%-95%, non-condensing\"] },\r\n          { section: \"\", item: \"Operating Altitude\", values: [\"<=2000 m\", \"<=2000 m\"] },\r\n          { section: \"Mechanical\", item: \"IP Rating\", values: [\"IP55\", \"IP55\"] },\r\n          { section: \"\", item: \"IK Rating\", values: [\"Cabinet IK10; screen IK08\", \"Cabinet IK10; screen IK08\"] },\r\n          { section: \"\", item: \"Noise\", values: [\"<=55 dB\", \"<=55 dB\"] },\r\n          { section: \"\", item: \"Cooling Mode\", values: [\"Air-cooled\", \"Air-cooled\"] },\r\n          { section: \"\", item: \"Charging Cable Length\", values: [\"5 m (optional)\", \"5 m (optional)\"] },\r\n          { section: \"\", item: \"Material\", values: [\"Stainless steel\", \"Stainless steel\"] },\r\n          { section: \"\", item: \"Dimensions\", values: [\"2300 x 860 x 590 mm\", \"2300 x 860 x 590 mm\"] },\r\n          { section: \"\", item: \"Weight\", values: [\"Approx. 340 kg\", \"Approx. 420 kg\"] },\r\n          { section: \"\", item: \"Installation\", values: [\"Floor-mounted\", \"Floor-mounted\"] }\r\n        ]\r\n      },\r\n      \"480kW\": {\r\n        variants: [\"240 kW\", \"360 kW\", \"480 kW\"],\r\n        rows: [\r\n          { section: \"Input\", item: \"Rated Voltage\", values: [\"400 Vac +\/-10%\", \"400 Vac +\/-10%\", \"400 Vac +\/-10%\"] },\r\n          { section: \"\", item: \"Rated Current\", values: [\"360 A\", \"540 A\", \"720 A\"] },\r\n          { section: \"Output\", item: \"Power\", values: [\"240 kW\", \"360 kW\", \"480 kW\"] },\r\n          { section: \"\", item: \"Connector Type (Optional)\", values: [\"CCS2 x2\", \"CCS2 x2\", \"CCS2 x2\"] },\r\n          { section: \"\", item: \"Voltage\", values: [\"150-1000 Vdc\", \"150-1000 Vdc\", \"150-1000 Vdc\"] },\r\n          { section: \"\", item: \"Current\", values: [\"250 A\", \"375 A\", \"375 A\"] },\r\n          { section: \"\", item: \"Efficiency\", values: [\">=97%\", \">=97%\", \">=97%\"] },\r\n          { section: \"\", item: \"Connector Quantity\", values: [\"Optional, max. 4\", \"Optional, max. 4\", \"Optional, max. 4\"] },\r\n          { section: \"Interaction\", item: \"Status LED\", values: [\"Per connector\", \"Per connector\", \"Per connector\"] },\r\n          { section: \"\", item: \"Meter\", values: [\"MID\", \"MID\", \"MID\"] },\r\n          { section: \"\", item: \"Activation Method\", values: [\"RFID \/ App \/ POS\", \"RFID \/ App \/ POS\", \"RFID \/ App \/ POS\"] },\r\n          { section: \"\", item: \"Network\", values: [\"Ethernet; 4G\", \"Ethernet; 4G\", \"Ethernet; 4G\"] },\r\n          { section: \"\", item: \"Screen\", values: [\"10-inch screen, 4 buttons\", \"10-inch screen, 4 buttons\", \"10-inch screen, 4 buttons\"] },\r\n          { section: \"\", item: \"Language\", values: [\"English (optional)\", \"English (optional)\", \"English (optional)\"] },\r\n          { section: \"\", item: \"POS\", values: [\"Optional\", \"Optional\", \"Optional\"] },\r\n          { section: \"\", item: \"Protocol\", values: [\"OCPP 1.6J\", \"OCPP 1.6J\", \"OCPP 1.6J\"] },\r\n          { section: \"Operating Conditions\", item: \"Operating Temperature\", values: [\"-30 C to 55 C\", \"-30 C to 55 C\", \"-30 C to 55 C\"] },\r\n          { section: \"\", item: \"Storage Temperature\", values: [\"-30 C to 70 C\", \"-30 C to 70 C\", \"-30 C to 70 C\"] },\r\n          { section: \"\", item: \"Relative Humidity\", values: [\"5%-95%, non-condensing\", \"5%-95%, non-condensing\", \"5%-95%, non-condensing\"] },\r\n          { section: \"\", item: \"Operating Altitude\", values: [\"<=2000 m\", \"<=2000 m\", \"<=2000 m\"] },\r\n          { section: \"Mechanical\", item: \"IP Rating\", values: [\"IP55\", \"IP55\", \"IP55\"] },\r\n          { section: \"\", item: \"IK Rating\", values: [\"Cabinet IK10; screen IK08\", \"Cabinet IK10; screen IK08\", \"Cabinet IK10; screen IK08\"] },\r\n          { section: \"\", item: \"Noise\", values: [\"<=55 dB\", \"<=55 dB\", \"<=55 dB\"] },\r\n          { section: \"\", item: \"Cooling Mode\", values: [\"Air (liquid optional)\", \"Air (liquid optional)\", \"Air (liquid optional)\"] },\r\n          { section: \"\", item: \"Charging Cable Length\", values: [\"5 m (optional)\", \"5 m (optional)\", \"5 m (optional)\"] },\r\n          { section: \"\", item: \"Material\", values: [\"Stainless steel\", \"Stainless steel\", \"Stainless steel\"] },\r\n          { section: \"\", item: \"Dimensions\", values: [\"2300 x 860 x 890 mm\", \"2300 x 860 x 890 mm\", \"2300 x 860 x 890 mm\"] },\r\n          { section: \"\", item: \"Weight\", values: [\"Approx. 460 kg\", \"Approx. 540 kg\", \"Approx. 620 kg\"] },\r\n          { section: \"\", item: \"Installation\", values: [\"Floor-mounted\", \"Floor-mounted\", \"Floor-mounted\"] }\r\n        ]\r\n      }\r\n    };\r\n\r\n    var BODY_COLOUR_PRESETS = [\r\n      { name: \"Glacier White\", value: \"#f8fafc\" },\r\n      { name: \"Signal White\", value: \"#ffffff\" },\r\n      { name: \"Warm White\", value: \"#f3f0e8\" },\r\n      { name: \"Pearl Silver\", value: \"#d7dce2\" },\r\n      { name: \"Cloud Grey\", value: \"#cbd5e1\" },\r\n      { name: \"Titanium Grey\", value: \"#8a95a3\" },\r\n      { name: \"Basalt Grey\", value: \"#4b5563\" },\r\n      { name: \"Graphite Grey\", value: \"#374151\" },\r\n      { name: \"Charcoal Blue\", value: \"#263241\" },\r\n      { name: \"Carbon Black\", value: \"#111827\" },\r\n      { name: \"Obsidian Black\", value: \"#05070a\" },\r\n      { name: \"Deep Navy\", value: \"#172554\" },\r\n      { name: \"Midnight Blue\", value: \"#1e3a5f\" },\r\n      { name: \"Slate Blue\", value: \"#334e68\" },\r\n      { name: \"Steel Blue\", value: \"#486581\" },\r\n      { name: \"Forest Green\", value: \"#1f4d3a\" },\r\n      { name: \"Pine Green\", value: \"#18392b\" },\r\n      { name: \"Sage Grey\", value: \"#7c8a7a\" },\r\n      { name: \"Urban Bronze\", value: \"#5c5146\" },\r\n      { name: \"Champagne Silver\", value: \"#c7b99b\" }\r\n    ];\r\n\r\n    var STRIPE_COLOUR_PRESETS = [\r\n      { name: \"Electric Cyan\", value: \"#00e5ff\" },\r\n      { name: \"Ice Blue\", value: \"#67e8f9\" },\r\n      { name: \"Clean Blue\", value: \"#0ea5e9\" },\r\n      { name: \"Azure Blue\", value: \"#2563eb\" },\r\n      { name: \"Deep Blue\", value: \"#1d4ed8\" },\r\n      { name: \"Indigo Accent\", value: \"#4f46e5\" },\r\n      { name: \"Violet Tech\", value: \"#7c3aed\" },\r\n      { name: \"Teal Pulse\", value: \"#14b8a6\" },\r\n      { name: \"Aqua Green\", value: \"#2dd4bf\" },\r\n      { name: \"Mint Glow\", value: \"#5eead4\" },\r\n      { name: \"Emerald Green\", value: \"#22c55e\" },\r\n      { name: \"Lime Signal\", value: \"#84cc16\" },\r\n      { name: \"Solar Yellow\", value: \"#facc15\" },\r\n      { name: \"Amber Signal\", value: \"#f59e0b\" },\r\n      { name: \"Safety Orange\", value: \"#f97316\" },\r\n      { name: \"Copper Orange\", value: \"#ea580c\" },\r\n      { name: \"Crimson Red\", value: \"#dc2626\" },\r\n      { name: \"Ruby Red\", value: \"#b91c1c\" },\r\n      { name: \"Magenta Signal\", value: \"#db2777\" },\r\n      { name: \"White Line\", value: \"#f8fafc\" }\r\n    ];\r\n\r\n    var nodes = {\r\n      modelButtons: root.querySelectorAll(\"[data-select-model]\"),\r\n      modelImages: root.querySelectorAll(\"[data-model-card-image]\"),\r\n      productTitle: root.querySelector(\"[data-product-title]\"),\r\n      stepIndicators: root.querySelectorAll(\"[data-step-indicator]\"),\r\n      stepPanes: root.querySelectorAll(\"[data-step-pane]\"),\r\n      content: root.querySelector(\"[data-configurator-content]\"),\r\n      powerOptions: root.querySelector(\"[data-power-options]\"),\r\n      optionInputs: root.querySelectorAll(\"[data-option]\"),\r\n      connectors: root.querySelector(\"[data-connectors]\"),\r\n      cableHint: root.querySelector(\"[data-cable-hint]\"),\r\n      backButton: root.querySelector(\"[data-back]\"),\r\n      nextButton: root.querySelector(\"[data-next]\"),\r\n      nextLabel: root.querySelector(\"[data-next-label]\"),\r\n      downloadButton: root.querySelector(\"[data-download]\"),\r\n      downloadLabel: root.querySelector(\"[data-download-label]\"),\r\n      contactButton: root.querySelector(\"[data-contact]\"),\r\n      summaryDetails: root.querySelector(\"[data-summary-details]\"),\r\n      resetButton: root.querySelector(\"[data-open-reset]\"),\r\n      resetModal: root.querySelector(\"[data-reset-modal]\"),\r\n      cancelResetButton: root.querySelector(\"[data-cancel-reset]\"),\r\n      confirmResetButton: root.querySelector(\"[data-confirm-reset]\"),\r\n      visualizer: root.querySelector(\"[data-visualizer]\"),\r\n      productPreview: root.querySelector(\"[data-product-preview]\"),\r\n      baseImage: root.querySelector(\"[data-base-image]\"),\r\n      powerImage: root.querySelector(\"[data-power-image]\"),\r\n      colourBaseImage: root.querySelector(\"[data-colour-base-image]\"),\r\n      layerGroups: root.querySelectorAll(\"[data-layer-group]\"),\r\n      connectorLayers: root.querySelectorAll(\"[data-connector-layer]\"),\r\n      colourConnectorLayers: root.querySelectorAll(\"[data-colour-connector-layer]\"),\r\n      summaryGalleryControls: root.querySelector(\"[data-summary-gallery-controls]\"),\r\n      summaryGalleryStatus: root.querySelector(\"[data-summary-gallery-status]\"),\r\n      summarySlideButtons: root.querySelectorAll(\"[data-summary-slide]\"),\r\n      bodyColourRect: root.querySelector(\"[data-body-colour-rect]\"),\r\n      stripeColourRect: root.querySelector(\"[data-stripe-colour-rect]\"),\r\n      colourTriggers: root.querySelectorAll(\"[data-colour-trigger]\"),\r\n      colourPalettes: root.querySelectorAll(\"[data-palette]\"),\r\n      bodyColourChip: root.querySelector('[data-colour-chip=\"body\"]'),\r\n      stripeColourChip: root.querySelector('[data-colour-chip=\"stripe\"]'),\r\n      bodyColourName: root.querySelector('[data-colour-name=\"body\"]'),\r\n      stripeColourName: root.querySelector('[data-colour-name=\"stripe\"]'),\r\n      customBodyColour: root.querySelector('[data-custom-colour=\"body\"]'),\r\n      customStripeColour: root.querySelector('[data-custom-colour=\"stripe\"]'),\r\n      customBodyHex: root.querySelector('[data-custom-hex=\"body\"]'),\r\n      customStripeHex: root.querySelector('[data-custom-hex=\"stripe\"]')\r\n    };\r\n\r\n    var currentStep = 1;\r\n    var highestStepReached = 1;\r\n    var state = createInitialState(null);\r\n    var resetReturnFocus = null;\r\n    var summarySlideIndex = SUMMARY_SLIDES.length - 1;\r\n    var summaryAnimationTimer = null;\r\n    var summaryPointer = {\r\n      id: null,\r\n      startX: 0,\r\n      startY: 0,\r\n      currentX: 0,\r\n      currentY: 0,\r\n      isDragging: false\r\n    };\r\n\r\n    function createInitialState(model) {\r\n      var selectedModel = model && MODEL_DATA[model] ? model : null;\r\n      var defaultPower = selectedModel\r\n        ? MODEL_DATA[selectedModel].powers[MODEL_DATA[selectedModel].powers.length - 1].value\r\n        : null;\r\n\r\n      return {\r\n        model: selectedModel,\r\n        power: defaultPower,\r\n        payment: false,\r\n        accessible: false,\r\n        doorContact: false,\r\n        connectors: { 1: null, 2: null, 3: null, 4: null },\r\n        bodyColourName: \"Glacier White\",\r\n        stripeColourName: \"Electric Cyan\",\r\n        bodyColour: \"#f8fafc\",\r\n        stripeColour: \"#00e5ff\"\r\n      };\r\n    }\r\n\r\n    function setBackgroundImage() {\r\n      function setImageProperty(propertyName, imageUrl) {\r\n        if (!imageUrl) {\r\n          root.style.setProperty(propertyName, \"none\");\r\n          return;\r\n        }\r\n\r\n        var safeUrl = String(imageUrl).replace(\/[\"\\\\]\/g, \"\\\\$&\");\r\n        root.style.setProperty(propertyName, 'url(\"' + safeUrl + '\")');\r\n      }\r\n\r\n      setImageProperty(\"--ec-configurator-background-image\", SETTINGS.backgroundImageUrl);\r\n      setImageProperty(\"--ec-selection-hover-background-image\", SETTINGS.selectionHoverBackgroundImageUrl);\r\n    }\r\n\r\n    function prepareAssets() {\r\n      root.querySelectorAll(\"img.ec-configurator__model-image, img.ec-configurator__layer\").forEach(function (image) {\r\n        image.addEventListener(\"error\", function () {\r\n          image.classList.add(\"is-asset-unavailable\");\r\n        });\r\n        image.addEventListener(\"load\", function () {\r\n          image.classList.remove(\"is-asset-unavailable\");\r\n        });\r\n      });\r\n\r\n      nodes.modelImages.forEach(function (image) {\r\n        var model = image.getAttribute(\"data-model-card-image\");\r\n        if (ASSETS[model]) image.src = ASSETS[model].baseNormal;\r\n      });\r\n\r\n      var masks = {\r\n        \"240-body\": ASSETS[\"240kW\"].maskBody,\r\n        \"480-body\": ASSETS[\"480kW\"].maskBody,\r\n        \"240-stripe\": ASSETS[\"240kW\"].maskStripe,\r\n        \"480-stripe\": ASSETS[\"480kW\"].maskStripe\r\n      };\r\n\r\n      Object.keys(masks).forEach(function (key) {\r\n        var mask = root.querySelector('[data-mask=\"' + key + '\"]');\r\n        if (mask) mask.setAttribute(\"href\", masks[key]);\r\n      });\r\n    }\r\n\r\n    function chooseModel(model) {\r\n      if (!MODEL_DATA[model]) return;\r\n      state = createInitialState(model);\r\n      highestStepReached = 1;\r\n      root.classList.remove(\"is-model-stage\");\r\n      root.classList.add(\"is-configuring\");\r\n      renderPowerOptions();\r\n      syncOptionControls();\r\n      renderConnectorOptions();\r\n      updateVisuals();\r\n      goToStep(2);\r\n    }\r\n\r\n    function returnToProductSelection() {\r\n      state = createInitialState(null);\r\n      currentStep = 1;\r\n      highestStepReached = 1;\r\n      setSummaryGalleryActive(false);\r\n      root.classList.add(\"is-model-stage\");\r\n      root.classList.remove(\"is-configuring\");\r\n      if (nodes.resetButton) nodes.resetButton.classList.add(\"is-hidden\");\r\n      closeResetModal();\r\n      if (nodes.content) nodes.content.scrollTop = 0;\r\n    }\r\n\r\n    function renderPowerOptions() {\r\n      if (!nodes.powerOptions || !state.model) return;\r\n      var model = MODEL_DATA[state.model];\r\n\r\n      nodes.powerOptions.innerHTML = model.powers.map(function (power) {\r\n        var checked = power.value === state.power ? \" checked\" : \"\";\r\n        return (\r\n          '<label class=\"ec-configurator__power-choice\">' +\r\n            '<input type=\"radio\" name=\"ec-power\" value=\"' + power.value + '\"' + checked + '>' +\r\n            '<span><strong>' + power.output + '<\/strong><small>' + power.modules + '<\/small><\/span>' +\r\n          '<\/label>'\r\n        );\r\n      }).join(\"\");\r\n    }\r\n\r\n    function escapeHtml(value) {\r\n      return String(value).replace(\/[&<>\\\"]\/g, function (character) {\r\n        return { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", \"\\\"\": \"&quot;\" }[character];\r\n      });\r\n    }\r\n\r\n    function syncOptionControls() {\r\n      nodes.optionInputs.forEach(function (input) {\r\n        var option = input.getAttribute(\"data-option\");\r\n        input.checked = Boolean(state[option]);\r\n      });\r\n    }\r\n\r\n    function getConnectorLengths(position) {\r\n      var restrictFiveMetres = state.model === \"480kW\" && (position === 2 || position === 3);\r\n      return restrictFiveMetres ? [\"3.5m\"] : [\"3.5m\", \"5m\"];\r\n    }\r\n\r\n    function getConnectorImageUrl(model, type, position, cable) {\r\n      var suffix = model === \"480kW\" && (position === 1 || position === 2) ? \"_1\" : \"\";\r\n      return SETTINGS.assetsBaseUrl + type + \"-\" + position + \"-\" + cable + suffix + \".webp\";\r\n    }\r\n\r\n    function connectorSelectMarkup(kind, position, selectedValue, choices, disabled) {\r\n      var controlId = \"ec-connector-\" + kind + \"-\" + position;\r\n      var selectedChoice = choices.find(function (choice) { return choice.value === selectedValue; }) || choices[0];\r\n      var classes = \"ec-configurator__connector-select\" + (disabled ? \" is-disabled\" : \"\");\r\n      var options = choices.map(function (choice) {\r\n        var selected = choice.value === selectedChoice.value;\r\n        return (\r\n          '<button class=\"ec-configurator__connector-choice' + (selected ? ' is-selected' : '') + '\" type=\"button\"' +\r\n            ' role=\"option\" aria-selected=\"' + (selected ? 'true' : 'false') + '\"' +\r\n            ' data-connector-choice data-connector-kind=\"' + kind + '\" data-connector-position=\"' + position + '\"' +\r\n            ' data-connector-value=\"' + escapeHtml(choice.value) + '\">' + escapeHtml(choice.label) + '<\/button>'\r\n        );\r\n      }).join(\"\");\r\n\r\n      return (\r\n        '<div class=\"' + classes + '\" data-connector-select>' +\r\n          '<button class=\"ec-configurator__connector-toggle\" type=\"button\" data-connector-toggle' +\r\n            ' data-connector-kind=\"' + kind + '\" data-connector-position=\"' + position + '\"' +\r\n            ' aria-expanded=\"false\" aria-controls=\"' + controlId + '\"' + (disabled ? ' disabled' : '') + '>' +\r\n            '<span>' + escapeHtml(selectedChoice.label) + '<\/span>' +\r\n            '<svg class=\"ec-configurator__connector-chevron\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 4l8 8-8 8\"><\/path><\/svg>' +\r\n          '<\/button>' +\r\n          '<div class=\"ec-configurator__connector-menu is-hidden\" id=\"' + controlId + '\" role=\"listbox\">' + options + '<\/div>' +\r\n        '<\/div>'\r\n      );\r\n    }\r\n\r\n    function renderConnectorOptions() {\r\n      if (!nodes.connectors || !state.model) return;\r\n      var model = MODEL_DATA[state.model];\r\n\r\n      if (nodes.cableHint) {\r\n        nodes.cableHint.classList.toggle(\"is-hidden\", state.model !== \"480kW\");\r\n      }\r\n\r\n      nodes.connectors.innerHTML = model.connectorPositions.map(function (position) {\r\n        var connector = state.connectors[position];\r\n        var lengths = getConnectorLengths(position);\r\n        if (connector && lengths.indexOf(connector.cable) === -1) connector.cable = lengths[0];\r\n\r\n        var typeChoices = [{ value: \"none\", label: \"None\" }].concat(CONNECTOR_TYPES.map(function (type) {\r\n          return { value: type, label: type };\r\n        }));\r\n        var lengthChoices = lengths.map(function (length) { return { value: length, label: length }; });\r\n        var selectedType = connector ? connector.type : \"none\";\r\n        var selectedLength = connector ? connector.cable : lengths[0];\r\n\r\n        return (\r\n          '<div class=\"ec-configurator__connector-row\" data-connector-row=\"' + position + '\">' +\r\n            '<span class=\"ec-configurator__connector-position\">Pos ' + position + '<\/span>' +\r\n            connectorSelectMarkup(\"type\", position, selectedType, typeChoices, false) +\r\n            connectorSelectMarkup(\"cable\", position, selectedLength, lengthChoices, !connector) +\r\n          '<\/div>'\r\n        );\r\n      }).join(\"\");\r\n    }\r\n\r\n    function closeConnectorMenus(exceptSelect) {\r\n      root.querySelectorAll(\"[data-connector-select]\").forEach(function (select) {\r\n        if (select === exceptSelect) return;\r\n        var menu = select.querySelector(\".ec-configurator__connector-menu\");\r\n        var toggle = select.querySelector(\"[data-connector-toggle]\");\r\n        select.classList.remove(\"is-open\", \"is-dropup\");\r\n        if (menu) {\r\n          menu.classList.add(\"is-hidden\");\r\n          menu.style.maxHeight = \"\";\r\n        }\r\n        if (toggle) toggle.setAttribute(\"aria-expanded\", \"false\");\r\n      });\r\n    }\r\n\r\n    function positionFloatingPanel(owner, trigger, panel) {\r\n      var boundary = nodes.content ? nodes.content.getBoundingClientRect() : root.getBoundingClientRect();\r\n      var triggerRect = trigger.getBoundingClientRect();\r\n      var rootFontSize = parseFloat(window.getComputedStyle(root).fontSize) || 16;\r\n      var gap = rootFontSize * 0.25;\r\n      var spaceBelow = Math.max(0, boundary.bottom - triggerRect.bottom - gap);\r\n      var spaceAbove = Math.max(0, triggerRect.top - boundary.top - gap);\r\n\r\n      owner.classList.remove(\"is-dropup\");\r\n      panel.style.maxHeight = \"\";\r\n\r\n      var cssLimit = parseFloat(window.getComputedStyle(panel).maxHeight);\r\n      var requiredHeight = Number.isFinite(cssLimit)\r\n        ? Math.min(panel.scrollHeight, cssLimit)\r\n        : panel.scrollHeight;\r\n      var opensUp = requiredHeight > spaceBelow && spaceAbove > spaceBelow;\r\n      var availableHeight = opensUp ? spaceAbove : spaceBelow;\r\n\r\n      owner.classList.toggle(\"is-dropup\", opensUp);\r\n      if (Number.isFinite(cssLimit)) {\r\n        panel.style.maxHeight = Math.max(0, Math.min(cssLimit, availableHeight)) + \"px\";\r\n      }\r\n    }\r\n\r\n    function toggleConnectorMenu(toggle) {\r\n      var select = toggle.closest(\"[data-connector-select]\");\r\n      var menu = select && select.querySelector(\".ec-configurator__connector-menu\");\r\n      if (!select || !menu || toggle.disabled) return;\r\n      var willOpen = menu.classList.contains(\"is-hidden\");\r\n      closeConnectorMenus();\r\n\r\n      if (willOpen) {\r\n        menu.classList.remove(\"is-hidden\");\r\n        select.classList.add(\"is-open\");\r\n        toggle.setAttribute(\"aria-expanded\", \"true\");\r\n        positionFloatingPanel(select, toggle, menu);\r\n      }\r\n    }\r\n\r\n    function setConnectorValue(kind, position, value) {\r\n      var connector = state.connectors[position];\r\n      if (kind === \"type\") {\r\n        if (value === \"none\") state.connectors[position] = null;\r\n        else state.connectors[position] = {\r\n          type: value,\r\n          cable: connector && getConnectorLengths(position).indexOf(connector.cable) !== -1\r\n            ? connector.cable\r\n            : getConnectorLengths(position)[0]\r\n        };\r\n      } else if (connector && getConnectorLengths(position).indexOf(value) !== -1) {\r\n        connector.cable = value;\r\n      }\r\n\r\n      renderConnectorOptions();\r\n      updateVisuals();\r\n    }\r\n\r\n    function getSummaryData() {\r\n      var model = MODEL_DATA[state.model];\r\n      var power = model.powers.find(function (item) { return item.value === state.power; });\r\n      var optionDefinitions = [\r\n        { key: \"payment\", label: \"Payment Terminal (POS)\" },\r\n        { key: \"accessible\", label: \"Accessible Screen Version\" },\r\n        { key: \"doorContact\", label: \"Door Contact Switch\" }\r\n      ];\r\n\r\n      return {\r\n        model: model.name,\r\n        power: power ? power.modules + \" - \" + power.output : \"Not selected\",\r\n        options: optionDefinitions.filter(function (option) { return state[option.key]; }).map(function (option) {\r\n          return { label: option.label, value: \"Selected\", checked: true };\r\n        }),\r\n        connectors: model.connectorPositions.map(function (position) {\r\n          var connector = state.connectors[position];\r\n          return {\r\n            label: \"Position \" + position,\r\n            value: connector ? connector.type + \", \" + connector.cable : \"None\"\r\n          };\r\n        }),\r\n        colours: [\r\n          { label: \"Body Finish\", value: state.bodyColourName + \" (\" + state.bodyColour.toUpperCase() + \")\" },\r\n          { label: \"Accent Stripe\", value: state.stripeColourName + \" (\" + state.stripeColour.toUpperCase() + \")\" }\r\n        ]\r\n      };\r\n    }\r\n\r\n    function summarySectionMarkup(title, rows) {\r\n      var resolvedRows = rows.length ? rows : [{ label: \"None\", value: \"\" }];\r\n      return (\r\n        '<section class=\"ec-configurator__summary-section\">' +\r\n          '<h3>' + escapeHtml(title) + '<\/h3>' +\r\n          '<div class=\"ec-configurator__summary-rows\">' +\r\n            resolvedRows.map(function (row) {\r\n              var check = row.checked\r\n                ? '<svg class=\"ec-configurator__summary-check\" viewBox=\"0 0 24 24\" aria-label=\"Selected\"><path d=\"M5 12.5l4.2 4.2L19 7\"><\/path><\/svg>'\r\n                : escapeHtml(row.value);\r\n              return (\r\n                '<div class=\"ec-configurator__summary-row' + (row.checked ? ' ec-configurator__summary-row--checked' : '') + '\">' +\r\n                  '<span class=\"ec-configurator__summary-label\">' + escapeHtml(row.label) + '<\/span>' +\r\n                  '<span class=\"ec-configurator__summary-value\">' + check + '<\/span>' +\r\n                '<\/div>'\r\n              );\r\n            }).join(\"\") +\r\n          '<\/div>' +\r\n        '<\/section>'\r\n      );\r\n    }\r\n\r\n    function renderSummary() {\r\n      if (!nodes.summaryDetails || !state.model) return;\r\n      var data = getSummaryData();\r\n      nodes.summaryDetails.innerHTML = [\r\n        summarySectionMarkup(\"Charger\", [\r\n          { label: \"Model\", value: data.model },\r\n          { label: \"Power Modules\", value: data.power }\r\n        ]),\r\n        summarySectionMarkup(\"Additional Options\", data.options),\r\n        summarySectionMarkup(\"Connectors\", data.connectors)\r\n      ].join(\"\");\r\n    }\r\n\r\n    function openContactPopup() {\r\n      var popupModule = window.elementorProFrontend && window.elementorProFrontend.modules\r\n        ? window.elementorProFrontend.modules.popup\r\n        : null;\r\n      if (popupModule && typeof popupModule.showPopup === \"function\") {\r\n        popupModule.showPopup({ id: SETTINGS.contactPopupId });\r\n        return;\r\n      }\r\n\r\n      root.dispatchEvent(new CustomEvent(\"ec:contact-request\", {\r\n        bubbles: true,\r\n        detail: { popupId: SETTINGS.contactPopupId }\r\n      }));\r\n    }\r\n\r\n    function openResetModal() {\r\n      if (!nodes.resetModal) return;\r\n      resetReturnFocus = document.activeElement;\r\n      nodes.resetModal.classList.remove(\"is-hidden\");\r\n      if (nodes.cancelResetButton) nodes.cancelResetButton.focus();\r\n    }\r\n\r\n    function closeResetModal() {\r\n      if (!nodes.resetModal) return;\r\n      var wasOpen = !nodes.resetModal.classList.contains(\"is-hidden\");\r\n      nodes.resetModal.classList.add(\"is-hidden\");\r\n      if (wasOpen && resetReturnFocus && typeof resetReturnFocus.focus === \"function\") resetReturnFocus.focus();\r\n      resetReturnFocus = null;\r\n    }\r\n\r\n    function pdfSafeText(value) {\r\n      return String(value).replace(\/[\\u2013\\u2014]\/g, \"-\").replace(\/[^\\x20-\\x7E]\/g, \"\").replace(\/[\\\\()]\/g, function (character) {\r\n        return \"\\\\\" + character;\r\n      });\r\n    }\r\n\r\n    function pdfTextOperation(text, x, y, size, bold, colour) {\r\n      var rgb = colour || [0.08, 0.1, 0.13];\r\n      return [\r\n        \"BT\",\r\n        rgb.join(\" \") + \" rg\",\r\n        \"\/\" + (bold ? \"F2\" : \"F1\") + \" \" + size + \" Tf\",\r\n        \"1 0 0 1 \" + x + \" \" + y + \" Tm\",\r\n        \"(\" + pdfSafeText(text) + \") Tj\",\r\n        \"ET\"\r\n      ].join(\"\\n\");\r\n    }\r\n\r\n    function pdfRectOperation(x, y, width, height, colour) {\r\n      return \"q \" + colour.join(\" \") + \" rg \" + x + \" \" + y + \" \" + width + \" \" + height + \" re f Q\";\r\n    }\r\n\r\n    function pdfLineOperation(x1, y1, x2, y2, colour, width) {\r\n      return \"q \" + colour.join(\" \") + \" RG \" + (width || 0.7) + \" w \" + x1 + \" \" + y1 + \" m \" + x2 + \" \" + y2 + \" l S Q\";\r\n    }\r\n\r\n    function truncatePdfText(value, maximumCharacters) {\r\n      var clean = String(value).replace(\/[\\u2013\\u2014]\/g, \"-\").replace(\/[^\\x20-\\x7E]\/g, \"\");\r\n      if (clean.length <= maximumCharacters) return clean;\r\n      return clean.slice(0, Math.max(0, maximumCharacters - 3)) + \"...\";\r\n    }\r\n\r\n    function pdfHexToRgb(hex) {\r\n      var normalised = String(hex || \"#000000\").replace(\"#\", \"\");\r\n      return [\r\n        parseInt(normalised.slice(0, 2), 16) \/ 255,\r\n        parseInt(normalised.slice(2, 4), 16) \/ 255,\r\n        parseInt(normalised.slice(4, 6), 16) \/ 255\r\n      ];\r\n    }\r\n\r\n    function pdfApproximateTextWidth(text, size) {\r\n      return String(text).length * size * 0.48;\r\n    }\r\n\r\n    function pdfCentredTextOperation(text, x, y, width, size, bold, colour) {\r\n      var maximumCharacters = Math.max(4, Math.floor(width \/ (size * 0.46)));\r\n      var clean = truncatePdfText(text, maximumCharacters);\r\n      var offset = Math.max(2, (width - pdfApproximateTextWidth(clean, size)) \/ 2);\r\n      return pdfTextOperation(clean, x + offset, y, size, bold, colour);\r\n    }\r\n\r\n    function loadPdfImage(source) {\r\n      return new Promise(function (resolve, reject) {\r\n        var image = new Image();\r\n        image.crossOrigin = \"anonymous\";\r\n        image.onload = function () { resolve(image); };\r\n        image.onerror = reject;\r\n        image.src = source;\r\n      });\r\n    }\r\n\r\n    async function capturePreviewJpeg() {\r\n      if (!state.model) return null;\r\n\r\n      try {\r\n        var assets = ASSETS[state.model];\r\n        var size = 720;\r\n        var canvas = document.createElement(\"canvas\");\r\n        var context = canvas.getContext(\"2d\");\r\n        canvas.width = size;\r\n        canvas.height = size;\r\n        context.fillStyle = \"#f4f6f8\";\r\n        context.fillRect(0, 0, size, size);\r\n\r\n        var baseImage;\r\n        try {\r\n          baseImage = await loadPdfImage(assets.colourBase);\r\n        } catch (colourBaseError) {\r\n          var baseKey = state.accessible\r\n            ? (state.payment ? \"baseAccessiblePos\" : \"baseAccessible\")\r\n            : (state.payment ? \"baseNormalPos\" : \"baseNormal\");\r\n          baseImage = await loadPdfImage(assets[baseKey]);\r\n        }\r\n        context.drawImage(baseImage, 0, 0, size, size);\r\n\r\n        async function tintMask(source, colour) {\r\n          try {\r\n            var mask = await loadPdfImage(source);\r\n            var tintCanvas = document.createElement(\"canvas\");\r\n            var tintContext = tintCanvas.getContext(\"2d\");\r\n            tintCanvas.width = size;\r\n            tintCanvas.height = size;\r\n            tintContext.drawImage(mask, 0, 0, size, size);\r\n            tintContext.globalCompositeOperation = \"source-in\";\r\n            tintContext.fillStyle = colour;\r\n            tintContext.fillRect(0, 0, size, size);\r\n            context.globalCompositeOperation = \"multiply\";\r\n            context.drawImage(tintCanvas, 0, 0);\r\n            context.globalCompositeOperation = \"source-over\";\r\n          } catch (maskError) {\r\n            context.globalCompositeOperation = \"source-over\";\r\n          }\r\n        }\r\n\r\n        await tintMask(assets.maskBody, state.bodyColour);\r\n        await tintMask(assets.maskStripe, state.stripeColour);\r\n\r\n        var positions = MODEL_DATA[state.model].connectorPositions;\r\n        for (var index = 0; index < positions.length; index += 1) {\r\n          var position = positions[index];\r\n          var connector = state.connectors[position];\r\n          if (!connector) continue;\r\n          try {\r\n            var connectorImage = await loadPdfImage(getConnectorImageUrl(state.model, connector.type, position, connector.cable));\r\n            context.drawImage(connectorImage, 0, 0, size, size);\r\n          } catch (connectorError) {\r\n            \/* The preview remains useful when an optional connector layer is unavailable. *\/\r\n          }\r\n        }\r\n\r\n        return await new Promise(function (resolve) {\r\n          canvas.toBlob(function (blob) {\r\n            if (!blob) {\r\n              resolve(null);\r\n              return;\r\n            }\r\n            var reader = new FileReader();\r\n            reader.onload = function () {\r\n              resolve({ bytes: new Uint8Array(reader.result), width: size, height: size });\r\n            };\r\n            reader.onerror = function () { resolve(null); };\r\n            reader.readAsArrayBuffer(blob);\r\n          }, \"image\/jpeg\", 0.92);\r\n        });\r\n      } catch (error) {\r\n        return null;\r\n      }\r\n    }\r\n\r\n    function buildConfigurationPageContent(data, hasImage) {\r\n      var operations = [];\r\n      var pageWidth = 612;\r\n      var margin = 36;\r\n      var lineColour = [0.81, 0.84, 0.87];\r\n      var muted = [0.38, 0.42, 0.46];\r\n      var ink = [0.06, 0.08, 0.1];\r\n\r\n      operations.push(pdfRectOperation(0, 728, pageWidth, 64, [0.025, 0.025, 0.028]));\r\n      operations.push(pdfRectOperation(0, 724, pageWidth, 4, [0.03, 0.91, 0.93]));\r\n      operations.push(pdfTextOperation(\"ELECREST\", margin, 758, 22, true, [1, 1, 1]));\r\n      operations.push(pdfTextOperation(\"HIMA CHARGER CONFIGURATION\", margin, 740, 8.5, false, [0.69, 0.72, 0.75]));\r\n      operations.push(pdfTextOperation(\"Configuration Summary\", margin, 690, 20, true, ink));\r\n      operations.push(pdfTextOperation(\"Your selected charger configuration at a glance.\", margin, 672, 9, false, muted));\r\n\r\n      operations.push(pdfRectOperation(margin, 348, 248, 302, [0.965, 0.972, 0.98]));\r\n      operations.push(pdfLineOperation(margin, 348, margin + 248, 348, lineColour));\r\n      operations.push(pdfLineOperation(margin, 650, margin + 248, 650, lineColour));\r\n      operations.push(pdfLineOperation(margin, 348, margin, 650, lineColour));\r\n      operations.push(pdfLineOperation(margin + 248, 348, margin + 248, 650, lineColour));\r\n      if (hasImage) {\r\n        operations.push(\"q 232 0 0 232 44 397 cm \/Im1 Do Q\");\r\n      } else {\r\n        operations.push(pdfTextOperation(\"Product preview unavailable\", 91, 500, 10, false, [0.58, 0.62, 0.66]));\r\n      }\r\n      operations.push(pdfTextOperation(data.model, 54, 374, 16, true, ink));\r\n      operations.push(pdfTextOperation(\"Configured product preview\", 54, 358, 8, false, muted));\r\n\r\n      var detailsX = 308;\r\n      var detailsWidth = 268;\r\n      operations.push(pdfRectOperation(detailsX, 580, detailsWidth, 70, [0.9, 0.985, 0.99]));\r\n      operations.push(pdfTextOperation(\"SELECTED MODEL\", detailsX + 15, 628, 8, true, muted));\r\n      operations.push(pdfTextOperation(data.model, detailsX + 15, 597, 22, true, ink));\r\n      operations.push(pdfRectOperation(detailsX, 507, detailsWidth, 60, [0.95, 0.96, 0.97]));\r\n      operations.push(pdfTextOperation(\"POWER CONFIGURATION\", detailsX + 15, 547, 8, true, muted));\r\n      operations.push(pdfTextOperation(truncatePdfText(data.power, 34), detailsX + 15, 523, 13, true, ink));\r\n\r\n      operations.push(pdfTextOperation(\"BODY FINISH\", detailsX, 479, 8, true, muted));\r\n      operations.push(pdfRectOperation(detailsX, 446, 22, 22, pdfHexToRgb(state.bodyColour)));\r\n      operations.push(pdfLineOperation(detailsX, 446, detailsX + 22, 446, lineColour));\r\n      operations.push(pdfLineOperation(detailsX, 468, detailsX + 22, 468, lineColour));\r\n      operations.push(pdfLineOperation(detailsX, 446, detailsX, 468, lineColour));\r\n      operations.push(pdfLineOperation(detailsX + 22, 446, detailsX + 22, 468, lineColour));\r\n      operations.push(pdfTextOperation(truncatePdfText(state.bodyColourName + \" (\" + state.bodyColour.toUpperCase() + \")\", 34), detailsX + 31, 452, 9.5, false, ink));\r\n\r\n      operations.push(pdfTextOperation(\"ACCENT STRIPE\", detailsX, 419, 8, true, muted));\r\n      operations.push(pdfRectOperation(detailsX, 386, 22, 22, pdfHexToRgb(state.stripeColour)));\r\n      operations.push(pdfLineOperation(detailsX, 386, detailsX + 22, 386, lineColour));\r\n      operations.push(pdfLineOperation(detailsX, 408, detailsX + 22, 408, lineColour));\r\n      operations.push(pdfLineOperation(detailsX, 386, detailsX, 408, lineColour));\r\n      operations.push(pdfLineOperation(detailsX + 22, 386, detailsX + 22, 408, lineColour));\r\n      operations.push(pdfTextOperation(truncatePdfText(state.stripeColourName + \" (\" + state.stripeColour.toUpperCase() + \")\", 34), detailsX + 31, 392, 9.5, false, ink));\r\n\r\n      var options = data.options.length\r\n        ? data.options.map(function (row) { return { label: row.label, value: \"Selected\" }; })\r\n        : [{ label: \"None\", value: \"\" }];\r\n      var selectionGroups = [\r\n        { title: \"Additional Options\", rows: options },\r\n        { title: \"Connectors\", rows: data.connectors }\r\n      ];\r\n      var y = 312;\r\n      selectionGroups.forEach(function (group) {\r\n        operations.push(pdfTextOperation(group.title, margin, y, 11, true, ink));\r\n        y -= 13;\r\n        operations.push(pdfLineOperation(margin, y, pageWidth - margin, y, lineColour));\r\n        y -= 20;\r\n        group.rows.forEach(function (row, index) {\r\n          if (index % 2 === 0) operations.push(pdfRectOperation(margin, y - 7, pageWidth - margin * 2, 22, [0.975, 0.98, 0.985]));\r\n          operations.push(pdfTextOperation(truncatePdfText(row.label, 43), margin + 10, y, 8.5, false, muted));\r\n          operations.push(pdfTextOperation(truncatePdfText(row.value, 46), 326, y, 8.5, true, ink));\r\n          y -= 22;\r\n        });\r\n        y -= 14;\r\n      });\r\n\r\n      operations.push(pdfLineOperation(margin, 42, pageWidth - margin, 42, lineColour));\r\n      operations.push(pdfTextOperation(\"Reference configuration. Final availability and compliance require Elecrest confirmation.\", margin, 25, 7.5, false, muted));\r\n      operations.push(pdfTextOperation(\"Page 1 of 2\", 526, 25, 7.5, false, muted));\r\n      return operations.join(\"\\n\");\r\n    }\r\n\r\n    function buildParameterPageContent(data) {\r\n      var specification = PARAMETER_TABLES[state.model] || PARAMETER_TABLES[\"240kW\"];\r\n      var variants = specification.variants;\r\n      var rows = specification.rows;\r\n      var pageWidth = 612;\r\n      var tableX = 30;\r\n      var tableWidth = pageWidth - 60;\r\n      var sectionWidth = 82;\r\n      var itemWidth = 150;\r\n      var valueAreaWidth = tableWidth - sectionWidth - itemWidth;\r\n      var valueWidth = valueAreaWidth \/ variants.length;\r\n      var headerHeight = 24;\r\n      var rowHeight = 22;\r\n      var tableTop = 722;\r\n      var headerY = tableTop - headerHeight;\r\n      var tableBottom = headerY - rows.length * rowHeight;\r\n      var itemX = tableX + sectionWidth;\r\n      var valueX = itemX + itemWidth;\r\n      var selectedPower = data.power;\r\n      var lineColour = [0.77, 0.81, 0.84];\r\n      var ink = [0.06, 0.08, 0.1];\r\n      var muted = [0.28, 0.32, 0.36];\r\n      var operations = [];\r\n\r\n      function valuesEqual(values) {\r\n        return values.every(function (value) { return value === values[0]; });\r\n      }\r\n\r\n      function sectionEnd(startIndex) {\r\n        for (var index = startIndex + 1; index < rows.length; index += 1) {\r\n          if (rows[index].section) return index;\r\n        }\r\n        return rows.length;\r\n      }\r\n\r\n      function centred(text, x, y, width, size, bold, colour) {\r\n        return pdfCentredTextOperation(text, x, y, width, size, bold, colour);\r\n      }\r\n\r\n      function wrappedCentred(text, x, y, width, height, size, bold, colour) {\r\n        var maximumCharacters = Math.max(7, Math.floor(width \/ (size * 0.47)));\r\n        var words = String(text).split(\" \");\r\n        var lines = [];\r\n        var line = \"\";\r\n        words.forEach(function (word) {\r\n          var next = line ? line + \" \" + word : word;\r\n          if (next.length > maximumCharacters && line) {\r\n            lines.push(line);\r\n            line = word;\r\n          } else {\r\n            line = next;\r\n          }\r\n        });\r\n        if (line) lines.push(line);\r\n        lines = lines.slice(0, 3);\r\n        var startY = y + height \/ 2 + ((lines.length - 1) * size * 0.58) - size * 0.32;\r\n        return lines.map(function (currentLine, index) {\r\n          return centred(currentLine, x, startY - index * size * 1.18, width, size, bold, colour);\r\n        }).join(\"\\n\");\r\n      }\r\n\r\n      operations.push(pdfRectOperation(0, 728, pageWidth, 64, [0.025, 0.025, 0.028]));\r\n      operations.push(pdfRectOperation(0, 724, pageWidth, 4, [0.03, 0.91, 0.93]));\r\n      operations.push(pdfTextOperation(\"TECHNICAL PARAMETER TABLE\", 30, 758, 17, true, [1, 1, 1]));\r\n      operations.push(pdfTextOperation(data.model + \" reference specification\", 30, 740, 8.5, false, [0.69, 0.72, 0.75]));\r\n\r\n      operations.push(pdfRectOperation(tableX, headerY, tableWidth, headerHeight, [0.04, 0.69, 0.73]));\r\n      operations.push(centred(\"Category\", tableX, headerY + 8, sectionWidth, 8, true, [1, 1, 1]));\r\n      operations.push(centred(\"Parameter\", itemX, headerY + 8, itemWidth, 8, true, [1, 1, 1]));\r\n      variants.forEach(function (variant, index) {\r\n        var isSelected = selectedPower.indexOf(variant) !== -1;\r\n        if (isSelected) operations.push(pdfRectOperation(valueX + valueWidth * index, headerY, valueWidth, headerHeight, [0.02, 0.52, 0.56]));\r\n        operations.push(centred(variant + (isSelected ? \" - selected\" : \"\"), valueX + valueWidth * index, headerY + 8, valueWidth, 7.6, true, [1, 1, 1]));\r\n        if (index > 0) operations.push(pdfLineOperation(valueX + valueWidth * index, headerY, valueX + valueWidth * index, tableTop, [1, 1, 1]));\r\n      });\r\n\r\n      rows.forEach(function (row, rowIndex) {\r\n        var rowY = headerY - rowHeight * (rowIndex + 1);\r\n        if (rowIndex % 2 === 0) operations.push(pdfRectOperation(itemX, rowY, itemWidth + valueAreaWidth, rowHeight, [0.97, 0.98, 0.985]));\r\n        variants.forEach(function (variant, variantIndex) {\r\n          if (!valuesEqual(row.values) && selectedPower.indexOf(variant) !== -1) {\r\n            operations.push(pdfRectOperation(valueX + valueWidth * variantIndex, rowY, valueWidth, rowHeight, [0.9, 0.985, 0.99]));\r\n          }\r\n        });\r\n\r\n        if (row.section) {\r\n          var end = sectionEnd(rowIndex);\r\n          var sectionHeight = rowHeight * (end - rowIndex);\r\n          var sectionY = headerY - rowHeight * end;\r\n          operations.push(pdfRectOperation(tableX, sectionY, sectionWidth, sectionHeight, [0.93, 0.97, 0.98]));\r\n          operations.push(wrappedCentred(row.section, tableX + 3, sectionY, sectionWidth - 6, sectionHeight, 7.3, true, ink));\r\n          operations.push(pdfLineOperation(tableX, rowY + rowHeight, tableX + tableWidth, rowY + rowHeight, [0.04, 0.69, 0.73], 0.9));\r\n        }\r\n\r\n        operations.push(pdfTextOperation(truncatePdfText(row.item, 29), itemX + 6, rowY + 7, 7.7, false, muted));\r\n        if (valuesEqual(row.values)) {\r\n          operations.push(centred(row.values[0], valueX, rowY + 7, valueAreaWidth, 7.5, false, ink));\r\n        } else {\r\n          row.values.forEach(function (value, valueIndex) {\r\n            operations.push(centred(value, valueX + valueWidth * valueIndex, rowY + 7, valueWidth, 7.5, false, ink));\r\n          });\r\n          for (var dividerIndex = 1; dividerIndex < variants.length; dividerIndex += 1) {\r\n            operations.push(pdfLineOperation(valueX + valueWidth * dividerIndex, rowY, valueX + valueWidth * dividerIndex, rowY + rowHeight, lineColour));\r\n          }\r\n        }\r\n        operations.push(pdfLineOperation(itemX, rowY, tableX + tableWidth, rowY, lineColour));\r\n      });\r\n\r\n      [tableX, itemX, valueX, tableX + tableWidth].forEach(function (x) {\r\n        operations.push(pdfLineOperation(x, tableBottom, x, tableTop, lineColour));\r\n      });\r\n      operations.push(pdfLineOperation(tableX, tableTop, tableX + tableWidth, tableTop, lineColour));\r\n      operations.push(pdfLineOperation(tableX, headerY, tableX + tableWidth, headerY, lineColour));\r\n      operations.push(pdfLineOperation(tableX, tableBottom, tableX + tableWidth, tableBottom, lineColour));\r\n      operations.push(pdfLineOperation(30, 42, pageWidth - 30, 42, lineColour));\r\n      operations.push(pdfTextOperation(\"Reference data only. Confirm the final specification with Elecrest sales engineering.\", 30, 25, 7.5, false, [0.38, 0.42, 0.46]));\r\n      operations.push(pdfTextOperation(\"Page 2 of 2\", 526, 25, 7.5, false, [0.38, 0.42, 0.46]));\r\n      return operations.join(\"\\n\");\r\n    }\r\n\r\n    function encodePdfPart(part) {\r\n      return part instanceof Uint8Array ? part : new TextEncoder().encode(part);\r\n    }\r\n\r\n    function buildPdfDocument(objects) {\r\n      var chunks = [];\r\n      var offsets = [0];\r\n      var length = 0;\r\n\r\n      function push(part) {\r\n        var encoded = encodePdfPart(part);\r\n        chunks.push(encoded);\r\n        length += encoded.length;\r\n      }\r\n\r\n      push(\"%PDF-1.4\\n\");\r\n      objects.forEach(function (object, index) {\r\n        offsets.push(length);\r\n        push((index + 1) + \" 0 obj\\n\");\r\n        object.parts.forEach(push);\r\n        push(\"\\nendobj\\n\");\r\n      });\r\n      var crossReferenceOffset = length;\r\n      push(\"xref\\n0 \" + (objects.length + 1) + \"\\n0000000000 65535 f \\n\");\r\n      offsets.slice(1).forEach(function (offset) {\r\n        push(String(offset).padStart(10, \"0\") + \" 00000 n \\n\");\r\n      });\r\n      push(\"trailer\\n<< \/Size \" + (objects.length + 1) + \" \/Root 1 0 R >>\\nstartxref\\n\" + crossReferenceOffset + \"\\n%%EOF\");\r\n\r\n      var output = new Uint8Array(length);\r\n      var cursor = 0;\r\n      chunks.forEach(function (chunk) {\r\n        output.set(chunk, cursor);\r\n        cursor += chunk.length;\r\n      });\r\n      return output;\r\n    }\r\n\r\n    function buildPdfBinary(previewImage) {\r\n      var data = getSummaryData();\r\n      var pageOne = buildConfigurationPageContent(data, Boolean(previewImage));\r\n      var pageTwo = buildParameterPageContent(data);\r\n      var pageOneLength = encodePdfPart(pageOne).length;\r\n      var pageTwoLength = encodePdfPart(pageTwo).length;\r\n\r\n      if (previewImage) {\r\n        return buildPdfDocument([\r\n          { parts: [\"<< \/Type \/Catalog \/Pages 2 0 R >>\"] },\r\n          { parts: [\"<< \/Type \/Pages \/Kids [3 0 R 4 0 R] \/Count 2 >>\"] },\r\n          { parts: [\"<< \/Type \/Page \/Parent 2 0 R \/MediaBox [0 0 612 792] \/Resources << \/Font << \/F1 5 0 R \/F2 6 0 R >> \/XObject << \/Im1 7 0 R >> >> \/Contents 8 0 R >>\"] },\r\n          { parts: [\"<< \/Type \/Page \/Parent 2 0 R \/MediaBox [0 0 612 792] \/Resources << \/Font << \/F1 5 0 R \/F2 6 0 R >> >> \/Contents 9 0 R >>\"] },\r\n          { parts: [\"<< \/Type \/Font \/Subtype \/Type1 \/BaseFont \/Helvetica >>\"] },\r\n          { parts: [\"<< \/Type \/Font \/Subtype \/Type1 \/BaseFont \/Helvetica-Bold >>\"] },\r\n          { parts: [\"<< \/Type \/XObject \/Subtype \/Image \/Width \" + previewImage.width + \" \/Height \" + previewImage.height + \" \/BitsPerComponent 8 \/ColorSpace \/DeviceRGB \/Filter \/DCTDecode \/Length \" + previewImage.bytes.length + \" >>\\nstream\\n\", previewImage.bytes, \"\\nendstream\"] },\r\n          { parts: [\"<< \/Length \" + pageOneLength + \" >>\\nstream\\n\" + pageOne + \"\\nendstream\"] },\r\n          { parts: [\"<< \/Length \" + pageTwoLength + \" >>\\nstream\\n\" + pageTwo + \"\\nendstream\"] }\r\n        ]);\r\n      }\r\n\r\n      return buildPdfDocument([\r\n        { parts: [\"<< \/Type \/Catalog \/Pages 2 0 R >>\"] },\r\n        { parts: [\"<< \/Type \/Pages \/Kids [3 0 R 4 0 R] \/Count 2 >>\"] },\r\n        { parts: [\"<< \/Type \/Page \/Parent 2 0 R \/MediaBox [0 0 612 792] \/Resources << \/Font << \/F1 5 0 R \/F2 6 0 R >> >> \/Contents 7 0 R >>\"] },\r\n        { parts: [\"<< \/Type \/Page \/Parent 2 0 R \/MediaBox [0 0 612 792] \/Resources << \/Font << \/F1 5 0 R \/F2 6 0 R >> >> \/Contents 8 0 R >>\"] },\r\n        { parts: [\"<< \/Type \/Font \/Subtype \/Type1 \/BaseFont \/Helvetica >>\"] },\r\n        { parts: [\"<< \/Type \/Font \/Subtype \/Type1 \/BaseFont \/Helvetica-Bold >>\"] },\r\n        { parts: [\"<< \/Length \" + pageOneLength + \" >>\\nstream\\n\" + pageOne + \"\\nendstream\"] },\r\n        { parts: [\"<< \/Length \" + pageTwoLength + \" >>\\nstream\\n\" + pageTwo + \"\\nendstream\"] }\r\n      ]);\r\n    }\r\n\r\n    async function buildConfigurationPdf() {\r\n      var previewImage = await capturePreviewJpeg();\r\n      return buildPdfBinary(previewImage);\r\n    }\r\n\r\n    async function downloadConfigurationPdf() {\r\n      if (!state.model || !nodes.downloadButton) return;\r\n      nodes.downloadButton.disabled = true;\r\n      if (nodes.downloadLabel) nodes.downloadLabel.textContent = \"Preparing PDF...\";\r\n\r\n      try {\r\n        var bytes = await buildConfigurationPdf();\r\n        var blob = new Blob([bytes], { type: \"application\/pdf\" });\r\n        var url = URL.createObjectURL(blob);\r\n        var link = document.createElement(\"a\");\r\n        link.href = url;\r\n        link.download = \"Elecrest-\" + MODEL_DATA[state.model].name.replace(\/\\s+\/g, \"-\") + \"-configuration.pdf\";\r\n        document.body.appendChild(link);\r\n        link.click();\r\n        link.remove();\r\n        window.setTimeout(function () { URL.revokeObjectURL(url); }, 1500);\r\n      } catch (error) {\r\n        window.console.error(\"The configuration PDF could not be generated.\", error);\r\n        root.dispatchEvent(new CustomEvent(\"ec:pdf-error\", { bubbles: true, detail: { error: error } }));\r\n      } finally {\r\n        nodes.downloadButton.disabled = false;\r\n        if (nodes.downloadLabel) nodes.downloadLabel.textContent = \"Download Configuration PDF\";\r\n      }\r\n    }\r\n\r\n    function getColourPresetList(kind) {\r\n      return kind === \"body\" ? BODY_COLOUR_PRESETS : STRIPE_COLOUR_PRESETS;\r\n    }\r\n\r\n    function normaliseHex(value) {\r\n      var text = String(value || \"\").trim();\r\n      return \/^#[0-9a-fA-F]{6}$\/.test(text) ? text.toLowerCase() : null;\r\n    }\r\n\r\n    function findColourPreset(kind, value) {\r\n      var normalisedValue = normaliseHex(value);\r\n      return getColourPresetList(kind).find(function (preset) {\r\n        return preset.value.toLowerCase() === normalisedValue;\r\n      }) || null;\r\n    }\r\n\r\n    function renderColourPresets() {\r\n      nodes.colourPalettes.forEach(function (palette) {\r\n        var kind = palette.getAttribute(\"data-palette\");\r\n        palette.innerHTML = getColourPresetList(kind).map(function (preset) {\r\n          return (\r\n            '<button class=\"ec-configurator__palette-option\" type=\"button\"' +\r\n              ' data-colour-option=\"' + kind + '\" data-colour-value=\"' + preset.value + '\"' +\r\n              ' data-colour-option-name=\"' + preset.name + '\" aria-label=\"Choose ' + preset.name + '\">' +\r\n              '<span class=\"ec-configurator__palette-chip\" style=\"background-color:' + preset.value + '\"><\/span>' +\r\n              '<span class=\"ec-configurator__palette-name\">' + preset.name + '<\/span>' +\r\n            '<\/button>'\r\n          );\r\n        }).join(\"\");\r\n      });\r\n    }\r\n\r\n    function closeColourPalettes(exceptKind) {\r\n      nodes.colourPalettes.forEach(function (palette) {\r\n        var kind = palette.getAttribute(\"data-palette\");\r\n        if (kind === exceptKind) return;\r\n        var picker = palette.closest(\"[data-colour-picker]\");\r\n        if (picker) picker.classList.remove(\"is-open\", \"is-dropup\");\r\n        palette.classList.add(\"is-hidden\");\r\n        palette.style.maxHeight = \"\";\r\n      });\r\n\r\n      nodes.colourTriggers.forEach(function (trigger) {\r\n        var kind = trigger.getAttribute(\"data-colour-trigger\");\r\n        if (kind !== exceptKind) trigger.setAttribute(\"aria-expanded\", \"false\");\r\n      });\r\n    }\r\n\r\n    function toggleColourPalette(kind) {\r\n      var palette = root.querySelector('[data-palette=\"' + kind + '\"]');\r\n      var trigger = root.querySelector('[data-colour-trigger=\"' + kind + '\"]');\r\n      var picker = trigger && trigger.closest(\"[data-colour-picker]\");\r\n      if (!palette || !trigger || !picker) return;\r\n\r\n      var willOpen = palette.classList.contains(\"is-hidden\");\r\n      closeColourPalettes();\r\n\r\n      if (willOpen) {\r\n        palette.classList.remove(\"is-hidden\");\r\n        picker.classList.add(\"is-open\");\r\n        trigger.setAttribute(\"aria-expanded\", \"true\");\r\n        positionFloatingPanel(picker, trigger, palette);\r\n      }\r\n    }\r\n\r\n    function updateColourUI() {\r\n      if (nodes.bodyColourRect) nodes.bodyColourRect.setAttribute(\"fill\", state.bodyColour);\r\n      if (nodes.stripeColourRect) nodes.stripeColourRect.setAttribute(\"fill\", state.stripeColour);\r\n      if (nodes.bodyColourChip) nodes.bodyColourChip.style.backgroundColor = state.bodyColour;\r\n      if (nodes.stripeColourChip) nodes.stripeColourChip.style.backgroundColor = state.stripeColour;\r\n      if (nodes.bodyColourName) nodes.bodyColourName.textContent = state.bodyColourName;\r\n      if (nodes.stripeColourName) nodes.stripeColourName.textContent = state.stripeColourName;\r\n      if (nodes.customBodyColour) nodes.customBodyColour.value = state.bodyColour;\r\n      if (nodes.customStripeColour) nodes.customStripeColour.value = state.stripeColour;\r\n      if (nodes.customBodyHex) nodes.customBodyHex.value = state.bodyColour.toUpperCase();\r\n      if (nodes.customStripeHex) nodes.customStripeHex.value = state.stripeColour.toUpperCase();\r\n\r\n      root.querySelectorAll(\"[data-colour-option]\").forEach(function (option) {\r\n        var kind = option.getAttribute(\"data-colour-option\");\r\n        var selectedValue = kind === \"body\" ? state.bodyColour : state.stripeColour;\r\n        var isSelected = option.getAttribute(\"data-colour-value\").toLowerCase() === selectedValue.toLowerCase();\r\n        option.classList.toggle(\"is-selected\", isSelected);\r\n        option.setAttribute(\"aria-pressed\", isSelected ? \"true\" : \"false\");\r\n      });\r\n    }\r\n\r\n    function setColour(kind, value, name) {\r\n      var normalisedValue = normaliseHex(value);\r\n      if (!normalisedValue) return false;\r\n      var preset = findColourPreset(kind, normalisedValue);\r\n      var resolvedName = name || (preset ? preset.name : (kind === \"body\" ? \"Custom Body\" : \"Custom Stripe\"));\r\n\r\n      if (kind === \"body\") {\r\n        state.bodyColour = normalisedValue;\r\n        state.bodyColourName = resolvedName;\r\n      } else {\r\n        state.stripeColour = normalisedValue;\r\n        state.stripeColourName = resolvedName;\r\n      }\r\n\r\n      updateColourUI();\r\n      return true;\r\n    }\r\n\r\n    function showLayer(name) {\r\n      nodes.layerGroups.forEach(function (group) {\r\n        var isTarget = group.getAttribute(\"data-layer-group\") === name;\r\n        group.classList.toggle(\"is-active\", isTarget);\r\n        group.classList.toggle(\"is-hidden\", !isTarget);\r\n      });\r\n    }\r\n\r\n    function getConfiguredBaseKey() {\r\n      return state.accessible\r\n        ? (state.payment ? \"baseAccessiblePos\" : \"baseAccessible\")\r\n        : (state.payment ? \"baseNormalPos\" : \"baseNormal\");\r\n    }\r\n\r\n    function updateConnectorLayerSet(layers, model) {\r\n      layers.forEach(function (layer) {\r\n        var attributeName = layer.hasAttribute(\"data-colour-connector-layer\")\r\n          ? \"data-colour-connector-layer\"\r\n          : \"data-connector-layer\";\r\n        var position = Number(layer.getAttribute(attributeName));\r\n        var connector = state.connectors[position];\r\n        if (!connector || model.connectorPositions.indexOf(position) === -1) {\r\n          layer.classList.add(\"is-hidden\");\r\n          layer.removeAttribute(\"src\");\r\n          return;\r\n        }\r\n\r\n        layer.src = getConnectorImageUrl(state.model, connector.type, position, connector.cable);\r\n        layer.alt = connector.type + \" connector at position \" + position + \" with a \" + connector.cable + \" cable\";\r\n        layer.classList.remove(\"is-hidden\");\r\n      });\r\n    }\r\n\r\n    function updateSummaryGalleryControls() {\r\n      var slide = SUMMARY_SLIDES[summarySlideIndex];\r\n      if (nodes.summaryGalleryStatus) {\r\n        nodes.summaryGalleryStatus.textContent = (summarySlideIndex + 1) + \" of \" + SUMMARY_SLIDES.length + \" \u2014 \" + slide.label;\r\n      }\r\n      nodes.summarySlideButtons.forEach(function (button) {\r\n        var isActive = Number(button.getAttribute(\"data-summary-slide\")) === summarySlideIndex;\r\n        button.classList.toggle(\"is-active\", isActive);\r\n        button.setAttribute(\"aria-pressed\", isActive ? \"true\" : \"false\");\r\n      });\r\n    }\r\n\r\n    function setSummaryGalleryActive(isActive) {\r\n      root.classList.toggle(\"is-summary-gallery\", isActive);\r\n      if (nodes.summaryGalleryControls) nodes.summaryGalleryControls.classList.toggle(\"is-hidden\", !isActive);\r\n      if (nodes.productPreview) {\r\n        if (isActive) {\r\n          nodes.productPreview.setAttribute(\"tabindex\", \"0\");\r\n          nodes.productPreview.setAttribute(\"role\", \"group\");\r\n          nodes.productPreview.setAttribute(\"aria-label\", \"Summary product preview. Drag left or right, or use the arrow keys, to review four looping stages.\");\r\n        } else {\r\n          nodes.productPreview.removeAttribute(\"tabindex\");\r\n          nodes.productPreview.removeAttribute(\"role\");\r\n          nodes.productPreview.removeAttribute(\"aria-label\");\r\n          nodes.productPreview.classList.remove(\"is-dragging\", \"is-slide-next\", \"is-slide-previous\");\r\n          nodes.productPreview.style.removeProperty(\"--ec-summary-drag-x\");\r\n        }\r\n      }\r\n      if (nodes.visualizer && !isActive) nodes.visualizer.classList.remove(\"is-dragging\");\r\n      if (!isActive) {\r\n        root.classList.remove(\"is-summary-initial\");\r\n        summaryPointer.id = null;\r\n        summaryPointer.isDragging = false;\r\n      }\r\n    }\r\n\r\n    function showSummarySlide(index, direction) {\r\n      if (!state.model) return false;\r\n      var requestedIndex = Number(index);\r\n      if (!Number.isFinite(requestedIndex)) return false;\r\n      var previousIndex = summarySlideIndex;\r\n      var nextIndex = Math.max(0, Math.min(SUMMARY_SLIDES.length - 1, requestedIndex));\r\n      var resolvedDirection = direction || (nextIndex >= previousIndex ? \"next\" : \"previous\");\r\n      summarySlideIndex = nextIndex;\r\n\r\n      var slide = SUMMARY_SLIDES[summarySlideIndex];\r\n      root.classList.toggle(\"is-summary-initial\", summarySlideIndex === 0);\r\n      if (summarySlideIndex === 0) {\r\n        nodes.baseImage.src = ASSETS[state.model].baseNormal;\r\n        nodes.baseImage.alt = MODEL_DATA[state.model].name + \" initial charger without connectors\";\r\n      } else if (summarySlideIndex === 2) {\r\n        nodes.baseImage.src = ASSETS[state.model][getConfiguredBaseKey()];\r\n        nodes.baseImage.alt = MODEL_DATA[state.model].name + \" configured charger\";\r\n      }\r\n\r\n      showLayer(slide.layer);\r\n      if (currentStep === 5 && nodes.productPreview && nextIndex !== previousIndex) {\r\n        window.clearTimeout(summaryAnimationTimer);\r\n        nodes.productPreview.classList.remove(\"is-slide-next\", \"is-slide-previous\");\r\n        void nodes.productPreview.offsetWidth;\r\n        nodes.productPreview.classList.add(resolvedDirection === \"previous\" ? \"is-slide-previous\" : \"is-slide-next\");\r\n        summaryAnimationTimer = window.setTimeout(function () {\r\n          nodes.productPreview.classList.remove(\"is-slide-next\", \"is-slide-previous\");\r\n        }, 300);\r\n      }\r\n      updateSummaryGalleryControls();\r\n      return true;\r\n    }\r\n\r\n    function moveSummarySlide(offset) {\r\n      var stepOffset = Number(offset);\r\n      if (!Number.isFinite(stepOffset) || stepOffset === 0) return false;\r\n      var targetIndex = (summarySlideIndex + stepOffset) % SUMMARY_SLIDES.length;\r\n      if (targetIndex < 0) targetIndex += SUMMARY_SLIDES.length;\r\n      return showSummarySlide(targetIndex, offset < 0 ? \"previous\" : \"next\");\r\n    }\r\n\r\n    function resetSummaryPointer() {\r\n      var pointerId = summaryPointer.id;\r\n      summaryPointer.id = null;\r\n      summaryPointer.isDragging = false;\r\n      if (nodes.visualizer) {\r\n        nodes.visualizer.classList.remove(\"is-dragging\");\r\n        if (pointerId !== null && nodes.visualizer.hasPointerCapture && nodes.visualizer.hasPointerCapture(pointerId)) {\r\n          try {\r\n            nodes.visualizer.releasePointerCapture(pointerId);\r\n          } catch (error) {\r\n            \/* The browser may already have released capture. *\/\r\n          }\r\n        }\r\n      }\r\n      if (nodes.productPreview) {\r\n        nodes.productPreview.style.removeProperty(\"--ec-summary-drag-x\");\r\n      }\r\n    }\r\n\r\n    function handleSummaryPointerDown(event) {\r\n      if (currentStep !== 5 || !event.isPrimary || (event.pointerType === \"mouse\" && event.button !== 0)) return;\r\n      if (event.target.closest(\"[data-summary-gallery-controls]\")) return;\r\n      summaryPointer.id = event.pointerId;\r\n      summaryPointer.startX = event.clientX;\r\n      summaryPointer.startY = event.clientY;\r\n      summaryPointer.currentX = event.clientX;\r\n      summaryPointer.currentY = event.clientY;\r\n      summaryPointer.isDragging = false;\r\n      window.clearTimeout(summaryAnimationTimer);\r\n      nodes.productPreview.classList.remove(\"is-slide-next\", \"is-slide-previous\");\r\n      if (nodes.visualizer && nodes.visualizer.setPointerCapture) {\r\n        try {\r\n          nodes.visualizer.setPointerCapture(event.pointerId);\r\n        } catch (error) {\r\n          \/* Synthetic pointer events may not own a browser pointer capture. *\/\r\n        }\r\n      }\r\n      if (event.pointerType === \"mouse\") event.preventDefault();\r\n    }\r\n\r\n    function handleSummaryPointerMove(event) {\r\n      if (currentStep !== 5 || event.pointerId !== summaryPointer.id) return;\r\n      summaryPointer.currentX = event.clientX;\r\n      summaryPointer.currentY = event.clientY;\r\n      var deltaX = summaryPointer.currentX - summaryPointer.startX;\r\n      var deltaY = summaryPointer.currentY - summaryPointer.startY;\r\n      if (!summaryPointer.isDragging && Math.abs(deltaX) >= 4 && Math.abs(deltaX) > Math.abs(deltaY)) {\r\n        summaryPointer.isDragging = true;\r\n        if (nodes.visualizer) nodes.visualizer.classList.add(\"is-dragging\");\r\n      }\r\n      if (!summaryPointer.isDragging) return;\r\n      var rootFontSize = parseFloat(window.getComputedStyle(root).fontSize) || 16;\r\n      var maxDelta = Math.max(48, nodes.productPreview.clientWidth * 0.28);\r\n      var boundedDelta = Math.max(-maxDelta, Math.min(maxDelta, deltaX));\r\n      nodes.productPreview.style.setProperty(\"--ec-summary-drag-x\", boundedDelta \/ rootFontSize + \"rem\");\r\n      event.preventDefault();\r\n    }\r\n\r\n    function handleSummaryPointerEnd(event) {\r\n      if (event.pointerId !== summaryPointer.id) return;\r\n      if (Number.isFinite(event.clientX)) summaryPointer.currentX = event.clientX;\r\n      if (Number.isFinite(event.clientY)) summaryPointer.currentY = event.clientY;\r\n      var deltaX = summaryPointer.currentX - summaryPointer.startX;\r\n      var threshold = Math.min(72, Math.max(36, nodes.productPreview.clientWidth * 0.08));\r\n      var shouldMove = summaryPointer.isDragging && Math.abs(deltaX) >= threshold;\r\n      resetSummaryPointer();\r\n      if (shouldMove) moveSummarySlide(deltaX < 0 ? 1 : -1);\r\n    }\r\n\r\n    function handleSummaryPointerCancel(event) {\r\n      if (event.pointerId === summaryPointer.id) resetSummaryPointer();\r\n    }\r\n\r\n    function handleSummaryKeydown(event) {\r\n      if (currentStep !== 5) return;\r\n      if (event.key === \"ArrowLeft\") {\r\n        event.preventDefault();\r\n        moveSummarySlide(-1);\r\n      } else if (event.key === \"ArrowRight\") {\r\n        event.preventDefault();\r\n        moveSummarySlide(1);\r\n      } else if (event.key === \"Home\") {\r\n        event.preventDefault();\r\n        showSummarySlide(0, \"previous\");\r\n      } else if (event.key === \"End\") {\r\n        event.preventDefault();\r\n        showSummarySlide(SUMMARY_SLIDES.length - 1, \"next\");\r\n      }\r\n    }\r\n\r\n    function updateVisuals() {\r\n      if (!state.model) return;\r\n      var assets = ASSETS[state.model];\r\n      var model = MODEL_DATA[state.model];\r\n      var power = model.powers.find(function (item) { return item.value === state.power; });\r\n\r\n      var baseKey = getConfiguredBaseKey();\r\n\r\n      nodes.productTitle.textContent = model.name;\r\n      nodes.baseImage.src = assets[baseKey];\r\n      nodes.baseImage.alt = model.name + \" configured charger\";\r\n      nodes.powerImage.src = power ? assets[power.imageKey] : assets.powerEmpty;\r\n      nodes.powerImage.alt = model.name + \" with \" + (power ? power.modules.toLowerCase() : \"no power modules\");\r\n      nodes.colourBaseImage.src = assets.colourBase;\r\n      nodes.colourBaseImage.alt = model.name + \" finish preview\";\r\n\r\n      nodes.bodyColourRect.setAttribute(\"fill\", state.bodyColour);\r\n      nodes.bodyColourRect.setAttribute(\"mask\", state.model === \"240kW\" ? \"url(#ec-body-mask-240)\" : \"url(#ec-body-mask-480)\");\r\n      nodes.stripeColourRect.setAttribute(\"fill\", state.stripeColour);\r\n      nodes.stripeColourRect.setAttribute(\"mask\", state.model === \"240kW\" ? \"url(#ec-stripe-mask-240)\" : \"url(#ec-stripe-mask-480)\");\r\n\r\n      updateColourUI();\r\n\r\n      updateConnectorLayerSet(nodes.connectorLayers, model);\r\n      updateConnectorLayerSet(nodes.colourConnectorLayers, model);\r\n    }\r\n\r\n    function updateStepIndicators() {\r\n      nodes.stepIndicators.forEach(function (indicator) {\r\n        var indicatorStep = Number(indicator.getAttribute(\"data-step-indicator\"));\r\n        var isActive = indicatorStep === currentStep;\r\n        var isAvailable = indicatorStep <= highestStepReached;\r\n\r\n        indicator.classList.toggle(\"is-active\", isActive);\r\n        indicator.classList.toggle(\"is-available\", isAvailable);\r\n        indicator.classList.toggle(\"is-complete\", isAvailable && !isActive);\r\n        indicator.disabled = !isAvailable;\r\n\r\n        if (isActive) indicator.setAttribute(\"aria-current\", \"step\");\r\n        else indicator.removeAttribute(\"aria-current\");\r\n\r\n        if (isAvailable) indicator.removeAttribute(\"aria-disabled\");\r\n        else indicator.setAttribute(\"aria-disabled\", \"true\");\r\n      });\r\n\r\n    }\r\n\r\n    function goToStep(step) {\r\n      if (step < 2 || step > 5 || !state.model) return;\r\n      currentStep = step;\r\n      highestStepReached = Math.max(highestStepReached, step);\r\n\r\n      setSummaryGalleryActive(step === 5);\r\n      if (step !== 5) updateVisuals();\r\n\r\n      nodes.stepPanes.forEach(function (pane) {\r\n        pane.classList.toggle(\"is-active\", Number(pane.getAttribute(\"data-step-pane\")) === step);\r\n      });\r\n\r\n      updateStepIndicators();\r\n\r\n      if (step === 2) showLayer(\"power\");\r\n      else if (step === 4) showLayer(\"colour\");\r\n      else if (step === 5) showSummarySlide(SUMMARY_SLIDES.length - 1);\r\n      else showLayer(\"closed\");\r\n\r\n      if (step !== 4) closeColourPalettes();\r\n      if (step !== 3) closeConnectorMenus();\r\n      if (step === 3) {\r\n        syncOptionControls();\r\n        renderConnectorOptions();\r\n      }\r\n\r\n      if (nodes.content) nodes.content.scrollTop = 0;\r\n      nodes.nextButton.classList.toggle(\"is-hidden\", step === 5);\r\n      nodes.downloadButton.classList.toggle(\"is-hidden\", step !== 5);\r\n      if (nodes.resetButton) nodes.resetButton.classList.toggle(\"is-hidden\", step !== 5);\r\n      if (step === 5) renderSummary();\r\n\r\n      var nextLabels = { 2: \"Config\", 3: \"Colour\", 4: \"Complete Configure\" };\r\n      if (nodes.nextLabel && nextLabels[step]) nodes.nextLabel.textContent = nextLabels[step];\r\n    }\r\n\r\n    function handleBack() {\r\n      if (currentStep === 2) {\r\n        returnToProductSelection();\r\n        return;\r\n      }\r\n      if (currentStep > 2) goToStep(currentStep - 1);\r\n    }\r\n\r\n    function handleNext() {\r\n      if (currentStep >= 2 && currentStep < 5) goToStep(currentStep + 1);\r\n    }\r\n\r\n    function bindEvents() {\r\n      nodes.modelButtons.forEach(function (button) {\r\n        button.addEventListener(\"click\", function () {\r\n          chooseModel(button.getAttribute(\"data-select-model\"));\r\n        });\r\n      });\r\n\r\n      nodes.stepIndicators.forEach(function (indicator) {\r\n        indicator.addEventListener(\"click\", function () {\r\n          if (indicator.disabled) return;\r\n          goToStep(Number(indicator.getAttribute(\"data-step-indicator\")));\r\n        });\r\n      });\r\n\r\n      nodes.summarySlideButtons.forEach(function (button) {\r\n        button.addEventListener(\"click\", function () {\r\n          showSummarySlide(Number(button.getAttribute(\"data-summary-slide\")));\r\n        });\r\n      });\r\n\r\n      if (nodes.productPreview) {\r\n        nodes.productPreview.addEventListener(\"keydown\", handleSummaryKeydown);\r\n        nodes.productPreview.querySelectorAll(\"img\").forEach(function (image) {\r\n          image.draggable = false;\r\n        });\r\n      }\r\n\r\n      if (nodes.visualizer) {\r\n        nodes.visualizer.addEventListener(\"pointerdown\", handleSummaryPointerDown);\r\n        nodes.visualizer.addEventListener(\"pointermove\", handleSummaryPointerMove);\r\n        nodes.visualizer.addEventListener(\"pointerup\", handleSummaryPointerEnd);\r\n        nodes.visualizer.addEventListener(\"pointercancel\", handleSummaryPointerCancel);\r\n        nodes.visualizer.addEventListener(\"lostpointercapture\", function (event) {\r\n          if (event.pointerId === summaryPointer.id) resetSummaryPointer();\r\n        });\r\n        nodes.visualizer.addEventListener(\"dragstart\", function (event) {\r\n          if (currentStep === 5) event.preventDefault();\r\n        });\r\n      }\r\n\r\n      nodes.powerOptions.addEventListener(\"change\", function (event) {\r\n        if (!event.target.matches('input[name=\"ec-power\"]')) return;\r\n        state.power = event.target.value;\r\n        updateVisuals();\r\n      });\r\n\r\n      nodes.optionInputs.forEach(function (input) {\r\n        input.addEventListener(\"change\", function () {\r\n          var option = input.getAttribute(\"data-option\");\r\n          state[option] = input.checked;\r\n          updateVisuals();\r\n        });\r\n      });\r\n\r\n      if (nodes.connectors) {\r\n        nodes.connectors.addEventListener(\"click\", function (event) {\r\n          var toggle = event.target.closest(\"[data-connector-toggle]\");\r\n          if (toggle && nodes.connectors.contains(toggle)) {\r\n            toggleConnectorMenu(toggle);\r\n            return;\r\n          }\r\n\r\n          var choice = event.target.closest(\"[data-connector-choice]\");\r\n          if (!choice || !nodes.connectors.contains(choice)) return;\r\n          setConnectorValue(\r\n            choice.getAttribute(\"data-connector-kind\"),\r\n            Number(choice.getAttribute(\"data-connector-position\")),\r\n            choice.getAttribute(\"data-connector-value\")\r\n          );\r\n        });\r\n      }\r\n\r\n      nodes.colourTriggers.forEach(function (trigger) {\r\n        trigger.addEventListener(\"click\", function () {\r\n          toggleColourPalette(trigger.getAttribute(\"data-colour-trigger\"));\r\n        });\r\n      });\r\n\r\n      nodes.colourPalettes.forEach(function (palette) {\r\n        palette.addEventListener(\"click\", function (event) {\r\n          var option = event.target.closest(\"[data-colour-option]\");\r\n          if (!option || !palette.contains(option)) return;\r\n          var kind = option.getAttribute(\"data-colour-option\");\r\n          setColour(kind, option.getAttribute(\"data-colour-value\"), option.getAttribute(\"data-colour-option-name\"));\r\n          closeColourPalettes();\r\n        });\r\n      });\r\n\r\n      [\"body\", \"stripe\"].forEach(function (kind) {\r\n        var colourInput = kind === \"body\" ? nodes.customBodyColour : nodes.customStripeColour;\r\n        var hexInput = kind === \"body\" ? nodes.customBodyHex : nodes.customStripeHex;\r\n\r\n        if (colourInput) {\r\n          colourInput.addEventListener(\"input\", function () {\r\n            setColour(kind, colourInput.value);\r\n          });\r\n        }\r\n\r\n        if (hexInput) {\r\n          hexInput.addEventListener(\"input\", function () {\r\n            if (setColour(kind, hexInput.value)) hexInput.removeAttribute(\"aria-invalid\");\r\n          });\r\n          hexInput.addEventListener(\"change\", function () {\r\n            var isValid = Boolean(normaliseHex(hexInput.value));\r\n            if (isValid) hexInput.removeAttribute(\"aria-invalid\");\r\n            else hexInput.setAttribute(\"aria-invalid\", \"true\");\r\n          });\r\n        }\r\n      });\r\n\r\n      nodes.backButton.addEventListener(\"click\", handleBack);\r\n      nodes.nextButton.addEventListener(\"click\", handleNext);\r\n      if (nodes.contactButton) nodes.contactButton.addEventListener(\"click\", openContactPopup);\r\n      if (nodes.downloadButton) nodes.downloadButton.addEventListener(\"click\", downloadConfigurationPdf);\r\n      if (nodes.resetButton) nodes.resetButton.addEventListener(\"click\", openResetModal);\r\n      if (nodes.cancelResetButton) nodes.cancelResetButton.addEventListener(\"click\", closeResetModal);\r\n      if (nodes.confirmResetButton) {\r\n        nodes.confirmResetButton.addEventListener(\"click\", function () {\r\n          closeResetModal();\r\n          returnToProductSelection();\r\n        });\r\n      }\r\n\r\n      root.addEventListener(\"click\", function (event) {\r\n        if (!event.target.closest(\"[data-connector-select]\")) closeConnectorMenus();\r\n        if (!event.target.closest(\"[data-colour-picker]\")) closeColourPalettes();\r\n      });\r\n    }\r\n\r\n    setBackgroundImage();\r\n    prepareAssets();\r\n    renderColourPresets();\r\n    updateColourUI();\r\n    bindEvents();\r\n\r\n    root.ecConfigurator = {\r\n      chooseModel: chooseModel,\r\n      goToStep: goToStep,\r\n      returnToProductSelection: returnToProductSelection,\r\n      setColour: setColour,\r\n      setConnectorValue: setConnectorValue,\r\n      renderSummary: renderSummary,\r\n      getSummaryData: getSummaryData,\r\n      openResetModal: openResetModal,\r\n      downloadConfigurationPdf: downloadConfigurationPdf,\r\n      buildPdfBinary: buildPdfBinary,\r\n      buildConfigurationPdf: buildConfigurationPdf,\r\n      capturePreviewJpeg: capturePreviewJpeg,\r\n      toggleColourPalette: toggleColourPalette,\r\n      showSummarySlide: showSummarySlide,\r\n      moveSummarySlide: moveSummarySlide,\r\n      getSummarySlideIndex: function () { return summarySlideIndex; },\r\n      getState: function () { return JSON.parse(JSON.stringify(state)); },\r\n      getCurrentStep: function () { return currentStep; },\r\n      settings: SETTINGS\r\n    };\r\n  }\r\n\r\n  function initialiseAllConfigurators() {\r\n    document.querySelectorAll(COMPONENT_SELECTOR).forEach(initialiseConfigurator);\r\n  }\r\n\r\n  if (document.readyState === \"loading\") {\r\n    document.addEventListener(\"DOMContentLoaded\", initialiseAllConfigurators, { once: true });\r\n  } else {\r\n    initialiseAllConfigurators();\r\n  }\r\n\r\n  window.addEventListener(\"elementor\/frontend\/init\", initialiseAllConfigurators);\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5ed4095 elementor-widget elementor-widget-html\" data-id=\"5ed4095\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section id=\"ec-configurator-app\" class=\"ec-configurator is-model-stage\" data-ec-configurator aria-label=\"Elecrest HIMA charger configurator\">\r\n  <div class=\"ec-configurator__model-stage\" data-model-stage>\r\n    <h1 class=\"ec-configurator__visually-hidden\">Choose a HIMA charger to configure<\/h1>\r\n\r\n    <article class=\"ec-configurator__model-card ec-configurator__model-card--480\">\r\n      <div class=\"ec-configurator__model-copy\">\r\n        <h2>HIMA 480<\/h2>\r\n        <p class=\"ec-configurator__model-lead\">Up to 480 kW<br>Quad connector<\/p>\r\n        <ul class=\"ec-configurator__model-facts\" aria-label=\"HIMA 480 highlights\">\r\n          <li><strong>97.5%<\/strong><span>Up to 97.5% efficiency under full load<\/span><\/li>\r\n          <li><strong>1200A<\/strong><span>Max total DC output 1200A (2x 600A)<\/span><\/li>\r\n          <li><strong>60kW<\/strong><span>Granularity for dynamic load management<\/span><\/li>\r\n          <li><strong>150\u20131000V<\/strong><span>Future-proof output range<\/span><\/li>\r\n        <\/ul>\r\n      <\/div>\r\n      <div class=\"ec-configurator__model-preview\" aria-hidden=\"true\">\r\n        <img decoding=\"async\" class=\"ec-configurator__model-image ec-configurator__model-image--base\" data-model-card-image=\"480kW\" src=\"\" alt=\"\">\r\n      <\/div>\r\n      <button class=\"ec-configurator__model-action\" type=\"button\" data-select-model=\"480kW\">Configure Now<\/button>\r\n    <\/article>\r\n\r\n    <article class=\"ec-configurator__model-card ec-configurator__model-card--240\">\r\n      <div class=\"ec-configurator__model-copy\">\r\n        <h2>HIMA 240<\/h2>\r\n        <p class=\"ec-configurator__model-lead\">Up to 240 kW<br>Dual connector<\/p>\r\n        <ul class=\"ec-configurator__model-facts\" aria-label=\"HIMA 240 highlights\">\r\n          <li><strong>97.5%<\/strong><span>Up to 97.5% efficiency under full load<\/span><\/li>\r\n          <li><strong>600A<\/strong><span>Max total DC output 600A<\/span><\/li>\r\n          <li><strong>60kW<\/strong><span>Granularity for dynamic load management<\/span><\/li>\r\n          <li><strong>150\u20131000V<\/strong><span>Future-proof output range<\/span><\/li>\r\n        <\/ul>\r\n      <\/div>\r\n      <div class=\"ec-configurator__model-preview\" aria-hidden=\"true\">\r\n        <img decoding=\"async\" class=\"ec-configurator__model-image ec-configurator__model-image--base\" data-model-card-image=\"240kW\" src=\"\" alt=\"\">\r\n      <\/div>\r\n      <button class=\"ec-configurator__model-action\" type=\"button\" data-select-model=\"240kW\">Configure Now<\/button>\r\n    <\/article>\r\n  <\/div>\r\n\r\n  <div class=\"ec-configurator__visualizer\" data-visualizer aria-live=\"polite\">\r\n    <div class=\"ec-configurator__product-preview\" data-product-preview>\r\n      <div class=\"ec-configurator__layer-group is-active\" data-layer-group=\"closed\">\r\n        <img decoding=\"async\" class=\"ec-configurator__layer ec-configurator__layer--base\" src=\"\" alt=\"\" data-base-image>\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-connector-layer=\"1\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-connector-layer=\"2\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-connector-layer=\"3\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-connector-layer=\"4\" alt=\"\">\r\n      <\/div>\r\n\r\n      <div class=\"ec-configurator__layer-group is-hidden\" data-layer-group=\"power\">\r\n        <img decoding=\"async\" class=\"ec-configurator__layer ec-configurator__layer--base\" src=\"\" alt=\"\" data-power-image>\r\n      <\/div>\r\n\r\n      <div class=\"ec-configurator__layer-group is-hidden\" data-layer-group=\"colour\">\r\n        <img decoding=\"async\" class=\"ec-configurator__layer ec-configurator__layer--base\" src=\"\" alt=\"\" data-colour-base-image>\r\n        <svg class=\"ec-configurator__layer ec-configurator__colour-layer\" viewBox=\"0 0 2400 2400\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n          <defs>\r\n            <mask id=\"ec-body-mask-240\" maskContentUnits=\"userSpaceOnUse\">\r\n              <image data-mask=\"240-body\" href=\"\" x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" preserveAspectRatio=\"none\"><\/image>\r\n            <\/mask>\r\n            <mask id=\"ec-body-mask-480\" maskContentUnits=\"userSpaceOnUse\">\r\n              <image data-mask=\"480-body\" href=\"\" x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" preserveAspectRatio=\"none\"><\/image>\r\n            <\/mask>\r\n          <\/defs>\r\n          <rect data-body-colour-rect x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" fill=\"#f8fafc\" mask=\"url(#ec-body-mask-480)\"><\/rect>\r\n        <\/svg>\r\n        <svg class=\"ec-configurator__layer ec-configurator__colour-layer\" viewBox=\"0 0 2400 2400\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n          <defs>\r\n            <mask id=\"ec-stripe-mask-240\" maskContentUnits=\"userSpaceOnUse\">\r\n              <image data-mask=\"240-stripe\" href=\"\" x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" preserveAspectRatio=\"none\"><\/image>\r\n            <\/mask>\r\n            <mask id=\"ec-stripe-mask-480\" maskContentUnits=\"userSpaceOnUse\">\r\n              <image data-mask=\"480-stripe\" href=\"\" x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" preserveAspectRatio=\"none\"><\/image>\r\n            <\/mask>\r\n          <\/defs>\r\n          <rect data-stripe-colour-rect x=\"0\" y=\"0\" width=\"2400\" height=\"2400\" fill=\"#00e5ff\" mask=\"url(#ec-stripe-mask-480)\"><\/rect>\r\n        <\/svg>\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-colour-connector-layer=\"1\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-colour-connector-layer=\"2\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-colour-connector-layer=\"3\" alt=\"\">\r\n        <img class=\"ec-configurator__layer ec-configurator__layer--connector is-hidden\" data-colour-connector-layer=\"4\" alt=\"\">\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"ec-configurator__summary-gallery-controls is-hidden\" data-summary-gallery-controls aria-label=\"Summary preview stages\">\r\n      <span class=\"ec-configurator__summary-gallery-status\" data-summary-gallery-status aria-live=\"polite\">4 of 4 \u2014 Final Colour<\/span>\r\n      <div class=\"ec-configurator__summary-gallery-progress\">\r\n        <div class=\"ec-configurator__summary-gallery-stages\">\r\n          <button type=\"button\" tabindex=\"-1\" data-summary-slide=\"0\" aria-label=\"Show initial product\" aria-pressed=\"false\"><\/button>\r\n          <button type=\"button\" tabindex=\"-1\" data-summary-slide=\"1\" aria-label=\"Show selected power modules\" aria-pressed=\"false\"><\/button>\r\n          <button type=\"button\" tabindex=\"-1\" data-summary-slide=\"2\" aria-label=\"Show configured product\" aria-pressed=\"false\"><\/button>\r\n          <button class=\"is-active\" type=\"button\" tabindex=\"-1\" data-summary-slide=\"3\" aria-label=\"Show final colour\" aria-pressed=\"true\"><\/button>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <section class=\"ec-configurator__panel\" data-panel aria-label=\"Configuration controls\">\r\n    <div class=\"ec-configurator__panel-heading\">\r\n      <h2 data-product-title>HIMA 480<\/h2>\r\n      <button class=\"ec-configurator__reset-button is-hidden\" type=\"button\" data-open-reset aria-label=\"Reset configuration\">\r\n        <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4 7h16M9 7V4h6v3m-8 0 1 13h8l1-13M10 11v5m4-5v5\"><\/path><\/svg>\r\n      <\/button>\r\n    <\/div>\r\n\r\n    <div class=\"ec-configurator__steps\" aria-label=\"Configuration progress\">\r\n      <button class=\"ec-configurator__step is-active is-available\" type=\"button\" data-step-indicator=\"2\" aria-current=\"step\">Power<\/button>\r\n      <button class=\"ec-configurator__step\" type=\"button\" data-step-indicator=\"3\" disabled aria-disabled=\"true\">Config<\/button>\r\n      <button class=\"ec-configurator__step\" type=\"button\" data-step-indicator=\"4\" disabled aria-disabled=\"true\">Colour<\/button>\r\n      <button class=\"ec-configurator__step\" type=\"button\" data-step-indicator=\"5\" disabled aria-disabled=\"true\">Summary<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"ec-configurator__content\" data-configurator-content>\r\n      <section class=\"ec-configurator__pane is-active\" data-step-pane=\"2\">\r\n        <div class=\"ec-configurator__group\">\r\n          <h3>Power Options<\/h3>\r\n          <div class=\"ec-configurator__choice-list\" data-power-options><\/div>\r\n        <\/div>\r\n        <div class=\"ec-configurator__section-intro\">\r\n          <h3>Select Power Modules<\/h3>\r\n          <p>View the internal architecture and select the number of power modules to install (120 kW per module).<\/p>\r\n        <\/div>\r\n      <\/section>\r\n\r\n      <section class=\"ec-configurator__pane\" data-step-pane=\"3\">\r\n        <div class=\"ec-configurator__group\">\r\n          <h3>Additional Options<\/h3>\r\n          <div class=\"ec-configurator__choice-list ec-configurator__choice-list--options\">\r\n            <label class=\"ec-configurator__option\">\r\n              <input type=\"checkbox\" data-option=\"payment\">\r\n              <span><span>Payment Terminal (POS)<\/span><span class=\"ec-configurator__option-mark\" aria-hidden=\"true\"><svg class=\"ec-configurator__option-plus\" viewBox=\"0 0 24 24\"><path d=\"M12 5v14M5 12h14\"><\/path><\/svg><svg class=\"ec-configurator__option-check\" viewBox=\"0 0 24 24\"><path d=\"M5 12.5l4.2 4.2L19 7\"><\/path><\/svg><\/span><\/span>\r\n            <\/label>\r\n            <label class=\"ec-configurator__option\">\r\n              <input type=\"checkbox\" data-option=\"accessible\">\r\n              <span><span>Accessible Screen Version<\/span><span class=\"ec-configurator__option-mark\" aria-hidden=\"true\"><svg class=\"ec-configurator__option-plus\" viewBox=\"0 0 24 24\"><path d=\"M12 5v14M5 12h14\"><\/path><\/svg><svg class=\"ec-configurator__option-check\" viewBox=\"0 0 24 24\"><path d=\"M5 12.5l4.2 4.2L19 7\"><\/path><\/svg><\/span><\/span>\r\n            <\/label>\r\n            <label class=\"ec-configurator__option\">\r\n              <input type=\"checkbox\" data-option=\"doorContact\">\r\n              <span><span>Door Contact Switch<\/span><span class=\"ec-configurator__option-mark\" aria-hidden=\"true\"><svg class=\"ec-configurator__option-plus\" viewBox=\"0 0 24 24\"><path d=\"M12 5v14M5 12h14\"><\/path><\/svg><svg class=\"ec-configurator__option-check\" viewBox=\"0 0 24 24\"><path d=\"M5 12.5l4.2 4.2L19 7\"><\/path><\/svg><\/span><\/span>\r\n            <\/label>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"ec-configurator__group ec-configurator__connector-group\">\r\n          <h3>Connector Configuration<\/h3>\r\n          <p class=\"ec-configurator__hint is-hidden\" data-cable-hint>Inner positions 2 and 3 on HIMA 480 do not support 5 m cables.<\/p>\r\n          <div class=\"ec-configurator__connectors\" data-connectors><\/div>\r\n        <\/div>\r\n      <\/section>\r\n\r\n      <section class=\"ec-configurator__pane\" data-step-pane=\"4\">\r\n        <div class=\"ec-configurator__group ec-configurator__colour-group\">\r\n          <h3>Body Finish<\/h3>\r\n          <div class=\"ec-configurator__colour-picker\" data-colour-picker=\"body\">\r\n            <button class=\"ec-configurator__colour-trigger\" type=\"button\" data-colour-trigger=\"body\" aria-expanded=\"false\" aria-controls=\"ec-body-palette\">\r\n              <span class=\"ec-configurator__colour-chip\" data-colour-chip=\"body\"><\/span>\r\n              <span data-colour-name=\"body\">Glacier White<\/span>\r\n              <svg class=\"ec-configurator__chevron\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 4l8 8-8 8\"><\/path><\/svg>\r\n            <\/button>\r\n            <div class=\"ec-configurator__palette is-hidden\" id=\"ec-body-palette\" data-palette=\"body\"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"ec-configurator__group ec-configurator__colour-group\">\r\n          <h3>Accent Stripe<\/h3>\r\n          <div class=\"ec-configurator__colour-picker\" data-colour-picker=\"stripe\">\r\n            <button class=\"ec-configurator__colour-trigger\" type=\"button\" data-colour-trigger=\"stripe\" aria-expanded=\"false\" aria-controls=\"ec-stripe-palette\">\r\n              <span class=\"ec-configurator__colour-chip\" data-colour-chip=\"stripe\"><\/span>\r\n              <span data-colour-name=\"stripe\">Electric Cyan<\/span>\r\n              <svg class=\"ec-configurator__chevron\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 4l8 8-8 8\"><\/path><\/svg>\r\n            <\/button>\r\n            <div class=\"ec-configurator__palette is-hidden\" id=\"ec-stripe-palette\" data-palette=\"stripe\"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"ec-configurator__group ec-configurator__custom-colours\">\r\n          <h3>Custom Fine Tuning<\/h3>\r\n          <p>Use custom colours only when a site brand guideline requires exact matching.<\/p>\r\n          <div class=\"ec-configurator__custom-colour-list\">\r\n            <label class=\"ec-configurator__custom-colour\">\r\n              <span>Body Colour<\/span>\r\n              <span class=\"ec-configurator__custom-colour-controls\">\r\n                <input type=\"color\" value=\"#f8fafc\" data-custom-colour=\"body\" aria-label=\"Choose a custom body colour\">\r\n                <input type=\"text\" value=\"#F8FAFC\" maxlength=\"7\" spellcheck=\"false\" data-custom-hex=\"body\" aria-label=\"Body colour hex value\">\r\n              <\/span>\r\n            <\/label>\r\n            <label class=\"ec-configurator__custom-colour\">\r\n              <span>Stripe Colour<\/span>\r\n              <span class=\"ec-configurator__custom-colour-controls\">\r\n                <input type=\"color\" value=\"#00e5ff\" data-custom-colour=\"stripe\" aria-label=\"Choose a custom stripe colour\">\r\n                <input type=\"text\" value=\"#00E5FF\" maxlength=\"7\" spellcheck=\"false\" data-custom-hex=\"stripe\" aria-label=\"Stripe colour hex value\">\r\n              <\/span>\r\n            <\/label>\r\n          <\/div>\r\n        <\/div>\r\n      <\/section>\r\n\r\n      <section class=\"ec-configurator__pane ec-configurator__summary\" data-step-pane=\"5\">\r\n        <div class=\"ec-configurator__summary-intro\">\r\n          <h3>Configuration Summary<\/h3>\r\n          <p>Review the final charger configuration, download the configuration sheet, or contact Elecrest for the next step.<\/p>\r\n          <button class=\"ec-configurator__contact-button\" type=\"button\" data-contact>Contact Us<\/button>\r\n        <\/div>\r\n        <div class=\"ec-configurator__summary-details\" data-summary-details><\/div>\r\n      <\/section>\r\n    <\/div>\r\n\r\n    <div class=\"ec-configurator__footer\">\r\n      <button class=\"ec-configurator__back-button\" type=\"button\" data-back aria-label=\"Go to the previous step\">\r\n        <svg class=\"ec-configurator__back-arrow\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M15 4l-8 8 8 8\"><\/path><\/svg>\r\n      <\/button>\r\n      <button class=\"ec-configurator__next-button\" type=\"button\" data-next>\r\n        <span data-next-label>Config<\/span>\r\n        <svg class=\"ec-configurator__next-arrow\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M8 4l8 8-8 8\"><\/path><\/svg>\r\n      <\/button>\r\n      <button class=\"ec-configurator__download-button is-hidden\" type=\"button\" data-download>\r\n        <span data-download-label>Download Configuration PDF<\/span>\r\n        <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 3v12m0 0 4-4m-4 4-4-4M4 15v5h16v-5\"><\/path><\/svg>\r\n      <\/button>\r\n    <\/div>\r\n  <\/section>\r\n\r\n  <div class=\"ec-configurator__modal is-hidden\" data-reset-modal role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"ec-reset-title\" aria-describedby=\"ec-reset-description\">\r\n    <div class=\"ec-configurator__modal-card\">\r\n      <h2 id=\"ec-reset-title\">Reconfiguration Confirmation<\/h2>\r\n      <p id=\"ec-reset-description\">After resetting, your charger configuration will return to the product selection screen. Continue?<\/p>\r\n      <div class=\"ec-configurator__modal-actions\">\r\n        <button type=\"button\" data-cancel-reset>Cancel<\/button>\r\n        <button type=\"button\" data-confirm-reset>Confirm<\/button>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Choose a HIMA charger to configure HIMA 480 Up to 480 kWQuad connector 97.5%Up to 97.5% efficiency under full load 1200AMax total DC output 1200A (2x 600A) 60kWGranularity for dynamic load management 150\u20131000VFuture-proof output range Configure Now HIMA 240 Up to 240 kWDual connector 97.5%Up to 97.5% efficiency under full load 600AMax total DC output [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-963","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/pages\/963","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/comments?post=963"}],"version-history":[{"count":72,"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/pages\/963\/revisions"}],"predecessor-version":[{"id":3786,"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/pages\/963\/revisions\/3786"}],"wp:attachment":[{"href":"https:\/\/elecrest.energy\/fr\/wp-json\/wp\/v2\/media?parent=963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}