{"id":23609,"date":"2026-02-09T13:03:23","date_gmt":"2026-02-09T13:03:23","guid":{"rendered":"https:\/\/ferroamp.com\/?page_id=23609"},"modified":"2026-02-09T15:18:19","modified_gmt":"2026-02-09T15:18:19","slug":"dimensioning-tool","status":"publish","type":"page","link":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/","title":{"rendered":"Dimensioning tool"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"23609\" class=\"elementor elementor-23609 elementor-21020\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-be5e5ee pt e-con-full full-width layout-no no e-flex e-con e-parent\" data-id=\"be5e5ee\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-cc8c796 container layout-no no e-flex e-con-boxed e-con e-child\" data-id=\"cc8c796\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div data-dce-title-color=\"#000000\" class=\"elementor-element elementor-element-ee503c2 elementor-widget elementor-widget-heading\" data-id=\"ee503c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Dimensioning tool<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-416a6c7 elementor-widget elementor-widget-text-editor\" data-id=\"416a6c7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Calculate how the Ferroamp system should be dimensioned and receive a complete documentation package.<\/p><p><strong>System calculator\u00a0<br \/><\/strong>Provides a complete bill of materials for the entire system, including PV string planning and DC cable sizing.<\/p><p><strong>SSO calculator\u00a0<br \/><\/strong>Used for calculating the PV panel configuration only. If the panels you intend to use are not available in the list, please send an email to <a href=\"mailto:improve@ferroamp.se\">improve@ferroamp.se.<\/a><\/p><p><strong>Cable calculator\u00a0<br \/><\/strong>Used for DC cable sizing. Choose between new cabling or the use of existing cabling.<\/p><p>Please note that the cable sizing applies to DC cabling (760 V) intended for use within the Ferroamp system.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-27f6ba5 container cut top-left medium e-con-full ts-toolsuite-container layout-no white e-flex e-con e-child\" data-id=\"27f6ba5\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-093f7d4 elementor-widget elementor-widget-template\" data-id=\"093f7d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"template.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-template\">\n\t\t\t\t\t<div data-elementor-type=\"container\" data-elementor-id=\"23601\" class=\"elementor elementor-23601 elementor-20702 elementor-20702\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b67e504 full-width layout-no no e-flex e-con-boxed e-con e-parent\" data-id=\"b67e504\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-071387e elementor-widget elementor-widget-dce-rawphp\" data-id=\"071387e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"dce-rawphp.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Dynamic PHP Raw -->\r\n\r\n\r\n<script>\r\nwindow.toolSuiteData = window.toolSuiteData || {};\r\n\r\nwindow.toolSuiteData.ssoPanels        = [{\"id\":\"0\",\"modell\":\"DMEGC 450 W FB - DM450M10RT-B54HBB\",\"pmax\":450,\"vmp\":33.24,\"voc\":39.8,\"imp\":13.54,\"isc\":14.04,\"voc_temp_coeff\":-0.25},{\"id\":\"1\",\"modell\":\"DMEGC 455 W FB - DM455G12RT-B48HBB\",\"pmax\":455,\"vmp\":34.11,\"voc\":40.45,\"imp\":13.34,\"isc\":14.24,\"voc_temp_coeff\":-0.25},{\"id\":\"2\",\"modell\":\"DMEGC 500 W FB - DM500M10RT-B60HBB\",\"pmax\":500,\"vmp\":37.66,\"voc\":44.7,\"imp\":13.3,\"isc\":14.22,\"voc_temp_coeff\":-0.25},{\"id\":\"3\",\"modell\":\"DMEGC 515W FB d.glas - DM515G12RT-G54HBB\",\"pmax\":515,\"vmp\":34.61,\"voc\":40.75,\"imp\":14.88,\"isc\":15.83,\"voc_temp_coeff\":-0.25},{\"id\":\"4\",\"modell\":\"DMEGC 465 W N helsv. - DM465G12RT-G48HBB\",\"pmax\":465,\"vmp\":31.21,\"voc\":36.46,\"imp\":14.91,\"isc\":15.88,\"voc_temp_coeff\":-0.25},{\"id\":\"5\",\"modell\":\"DMEGC 470 W N helsv. - DM470G12RT-G48HBB\",\"pmax\":470,\"vmp\":31.47,\"voc\":36.6,\"imp\":14.95,\"isc\":15.93,\"voc_temp_coeff\":-0.25},{\"id\":\"6\",\"modell\":\"HYUNDAI 435 W HG - HiE-S435HG(FB)\",\"pmax\":435,\"vmp\":36.2,\"voc\":43.6,\"imp\":12.02,\"isc\":12.79,\"voc_temp_coeff\":-0.27},{\"id\":\"7\",\"modell\":\"JA Solar 455 W - JAM54D41-455\\\/LB\",\"pmax\":455,\"vmp\":33.33,\"voc\":40.5,\"imp\":13.65,\"isc\":14.42,\"voc_temp_coeff\":-0.25},{\"id\":\"8\",\"modell\":\"JA Solar 500 W - JAM60D41-500\\\/LB\",\"pmax\":500,\"vmp\":38.26,\"voc\":45,\"imp\":13.07,\"isc\":14.05,\"voc_temp_coeff\":-0.25},{\"id\":\"9\",\"modell\":\"Leapton Solar 460 W - LP182*210-M-48-NB\",\"pmax\":460,\"vmp\":30.23,\"voc\":36.39,\"imp\":15.22,\"isc\":16.08,\"voc_temp_coeff\":-0.25},{\"id\":\"10\",\"modell\":\"Leapton Solar 510 W - LP182*210-M-54-NB\",\"pmax\":510,\"vmp\":33.73,\"voc\":40.57,\"imp\":15.12,\"isc\":16.01,\"voc_temp_coeff\":-0.25},{\"id\":\"11\",\"modell\":\"Leapton Solar 630 W - LP182*210-M-66-NB\",\"pmax\":630,\"vmp\":41.46,\"voc\":49.95,\"imp\":15.2,\"isc\":16.05,\"voc_temp_coeff\":-0.25},{\"id\":\"12\",\"modell\":\"Ledvance 590 W - M 590 N 72 LB -SF-F7\",\"pmax\":590,\"vmp\":42.92,\"voc\":51.88,\"imp\":13.75,\"isc\":14.48,\"voc_temp_coeff\":-0.26},{\"id\":\"13\",\"modell\":\"Longi 465 W Hi-MO X6-Max - LR7-54HTB\",\"pmax\":465,\"vmp\":33.54,\"voc\":39.71,\"imp\":13.8,\"isc\":14.77,\"voc_temp_coeff\":-0.23},{\"id\":\"14\",\"modell\":\"Sunpower 455 W FB d.glas - SPR-P7-455-BLK\",\"pmax\":455,\"vmp\":35.7,\"voc\":42.13,\"imp\":12.75,\"isc\":13.45,\"voc_temp_coeff\":-0.25},{\"id\":\"15\",\"modell\":\"Sunpower 510 W FB d.glas - SPR-P7-510-BLK-P\",\"pmax\":510,\"vmp\":39.69,\"voc\":47,\"imp\":12.85,\"isc\":13.56,\"voc_temp_coeff\":-0.25},{\"id\":\"16\",\"modell\":\"TCL solar 450 W d.glas tra. - HSM-ND48-GR450T\",\"pmax\":450,\"vmp\":30.13,\"voc\":35.56,\"imp\":14.94,\"isc\":16.06,\"voc_temp_coeff\":-0.25},{\"id\":\"17\",\"modell\":\"TCL solar 455 W FB d.glas - HSM-ND48-GR455\",\"pmax\":455,\"vmp\":30.32,\"voc\":35.76,\"imp\":15.01,\"isc\":16.13,\"voc_temp_coeff\":-0.25},{\"id\":\"18\",\"modell\":\"TCL solar 505 W FB d.glas - HSM-ND54-GR505\",\"pmax\":505,\"vmp\":33.9,\"voc\":40.14,\"imp\":14.9,\"isc\":15.88,\"voc_temp_coeff\":-0.25},{\"id\":\"19\",\"modell\":\"TCL solar 620 W d.glas - HSM-ND66-GR620\",\"pmax\":620,\"vmp\":40.98,\"voc\":48.94,\"imp\":14.13,\"isc\":16.05,\"voc_temp_coeff\":-0.25},{\"id\":\"20\",\"modell\":\"Trina 435 W - TSM-DE09R\",\"pmax\":435,\"vmp\":42.5,\"voc\":50.4,\"imp\":10.24,\"isc\":10.67,\"voc_temp_coeff\":-0.25},{\"id\":\"21\",\"modell\":\"Trina 440 W transparent - TSM-NEG9RC.27\",\"pmax\":440,\"vmp\":44,\"voc\":52.2,\"imp\":10.01,\"isc\":10.67,\"voc_temp_coeff\":-0.24},{\"id\":\"22\",\"modell\":\"Trina 450 W - TSM-NEG9R.28\",\"pmax\":450,\"vmp\":44.6,\"voc\":52.9,\"imp\":10.09,\"isc\":10.74,\"voc_temp_coeff\":-0.24},{\"id\":\"23\",\"modell\":\"Znshine Solar 380 W - ZXM6-NHLDD120\",\"pmax\":380,\"vmp\":34.6,\"voc\":41.2,\"imp\":10.91,\"isc\":11.43,\"voc_temp_coeff\":-0.29},{\"id\":\"24\",\"modell\":\"Znshine Solar 430 W - ZXM7-UHLDD108\",\"pmax\":430,\"vmp\":31.9,\"voc\":38.4,\"imp\":13.48,\"isc\":14.18,\"voc_temp_coeff\":-0.25},{\"id\":\"25\",\"modell\":\"Znshine Solar 480 W - ZXM7-UHLDD120\",\"pmax\":480,\"vmp\":35.5,\"voc\":42.8,\"imp\":13.53,\"isc\":14.31,\"voc_temp_coeff\":-0.25},{\"id\":\"26\",\"modell\":\"Leapton Solar 450 W - LP182*210-M-48-NB\",\"pmax\":450,\"vmp\":29.78,\"voc\":35.88,\"imp\":15.11,\"isc\":15.97,\"voc_temp_coeff\":-0.3},{\"id\":\"27\",\"modell\":\"Leapton Solar 500 W - LP182*210-M-54-NB\",\"pmax\":500,\"vmp\":33.33,\"voc\":40.07,\"imp\":15,\"isc\":15.9,\"voc_temp_coeff\":-0.3},{\"id\":\"28\",\"modell\":\"Leapton Solar 610 W - LP182*210-M-66-NB\",\"pmax\":610,\"vmp\":40.66,\"voc\":49.05,\"imp\":15,\"isc\":15.84,\"voc_temp_coeff\":-0.3}];\r\nwindow.toolSuiteData.ssoLimits        = {\"sso2_voc\":1000,\"SSO2_VOC\":1000,\"sso2_voc2\":720,\"SSO2_VOC2\":720,\"sso2_vmp_low\":100,\"SSO2_VMP_LOW\":100,\"sso2_vmp_high\":720,\"SSO2_VMP_HIGH\":720,\"sso2_isc_reduced\":13,\"SSO2_ISC_REDUCED\":13,\"sso2_imp_reduced\":12.5,\"SSO2_IMP_REDUCED\":12.5,\"sso2_imp_reduced2\":14,\"SSO2_IMP_REDUCED2\":14,\"sso2_imp_reduced3\":16,\"SSO2_IMP_REDUCED3\":16,\"sso2_imp_reduced_factor\":80,\"SSO2_IMP_REDUCED_FACTOR\":80};\r\n\r\nwindow.toolSuiteData.sysconfProducts  = [{\"enr\":\"5289206\",\"name\":\"EnergyHub 14 kW\",\"max_power\":16.8},{\"enr\":\"5289199\",\"name\":\"EnergyHub Wall 21 kW\",\"max_power\":25.2},{\"enr\":\"5289200\",\"name\":\"EnergyHub Wall 28 kW\",\"max_power\":33.6},{\"enr\":\"5289514\",\"name\":\"EnergyHub Rack 24U ink XL 21 kW\",\"max_power\":25.2},{\"enr\":\"5289205\",\"name\":\"EnergyHub XL 21 kW\",\"max_power\":25.2},{\"enr\":\"5289420\",\"name\":\"EnergyHub Rack 24U ink XL 28kW\",\"max_power\":33.6},{\"enr\":\"5289421\",\"name\":\"EnergyHub Rack 42U ink XL 28kW\",\"max_power\":33.6},{\"enr\":\"5289208\",\"name\":\"EnergyHub XL 28 kW\",\"max_power\":33.6},{\"enr\":\"2742064\",\"name\":\"Pylontech Force H3 module\",\"max_power\":null},{\"enr\":\"2742065\",\"name\":\"Pylontech Force H3 controller\",\"max_power\":null},{\"enr\":\"2740259\",\"name\":\"ESO 6 kW\",\"max_power\":null},{\"enr\":\"2740258\",\"name\":\"PowerCase\",\"max_power\":null},{\"enr\":\"5289195\",\"name\":\"SSO 8 kW\",\"max_power\":null},{\"enr\":\"5289181\",\"name\":\"Power Distribution 5\",\"max_power\":null},{\"enr\":\"5289180\",\"name\":\"Power Distribution 8\",\"max_power\":null},{\"enr\":\"5289182\",\"name\":\"Power Distribution 15\",\"max_power\":null},{\"enr\":\"52??????\",\"name\":\"ESO 15 kW\",\"max_power\":null},{\"enr\":\"-\",\"name\":\"Network switch minimum 4 ports\",\"max_power\":null}];\r\nwindow.toolSuiteData.sysconfBatteries = [{\"id\":\"0\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":10.24,\"modules\":2,\"controllers\":1},{\"id\":\"1\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":15.36,\"modules\":3,\"controllers\":1},{\"id\":\"2\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":20.48,\"modules\":4,\"controllers\":1},{\"id\":\"3\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":25.6,\"modules\":5,\"controllers\":1},{\"id\":\"4\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":30.72,\"modules\":6,\"controllers\":1},{\"id\":\"5\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":35.84,\"modules\":7,\"controllers\":2},{\"id\":\"6\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":40.96,\"modules\":8,\"controllers\":2},{\"id\":\"7\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":46.08,\"modules\":9,\"controllers\":2},{\"id\":\"8\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":51.2,\"modules\":10,\"controllers\":2},{\"id\":\"9\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":56.32,\"modules\":11,\"controllers\":2},{\"id\":\"10\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":61.44,\"modules\":12,\"controllers\":2},{\"id\":\"11\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":66.56,\"modules\":13,\"controllers\":3},{\"id\":\"12\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":71.68,\"modules\":14,\"controllers\":3},{\"id\":\"13\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":76.8,\"modules\":15,\"controllers\":3},{\"id\":\"14\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":81.92,\"modules\":16,\"controllers\":3},{\"id\":\"15\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":87.04,\"modules\":17,\"controllers\":3},{\"id\":\"16\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":92.16,\"modules\":18,\"controllers\":3}];\r\n\r\nwindow.toolSuiteData.cableCables      = [];\r\nwindow.toolSuiteData.cableInstalls    = [];\r\nwindow.toolSuiteData.cableProfiles    = [];\r\n\r\n\/\/ Legacy exports (om n\u00e5got gammalt script r\u00e5kar anv\u00e4nda dem)\r\nwindow.ssoPanels = window.toolSuiteData.ssoPanels;\r\nwindow.ssoLimits = window.toolSuiteData.ssoLimits;\r\n<\/script>\r\n\r\n\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3837a02 elementor-widget-tablet_extra__width-initial elementor-widget elementor-widget-html\" data-id=\"3837a02\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n  \/* -----------------------------------------------------------\r\n     1. VARIABLER & GLOBAL SCOPE\r\n  ----------------------------------------------------------- *\/\r\n  :root {\r\n    --fa-green: #7fb52f;\r\n    --fa-green-dark: #6e9e26; \/* Justerad f\u00f6r att vara lite m\u00f6rkare vid active\/hover-p\u00e5-active *\/\r\n    --fa-border: #7fb52f;\r\n    --ts-max: 900px;\r\n    --ts-pad: 24px;\r\n    --ts-text: #111;\r\n  }\r\n\r\n  .ts-hidden {\r\n    display: none !important;\r\n  }\r\n\r\n  \/* -----------------------------------------------------------\r\n     2. OUTER BREAKOUT (Ligger utanf\u00f6r #toolSuiteWrap)\r\n  ----------------------------------------------------------- *\/\r\n  .ts-breakout {\r\n    width: 100vw !important;\r\n    max-width: 100vw !important;\r\n    margin-left: calc(50% - 50vw) !important;\r\n    margin-right: calc(50% - 50vw) !important;\r\n    box-sizing: border-box !important;\r\n    position: relative !important;\r\n    left: auto !important;\r\n    right: auto !important;\r\n    padding: 0 !important;\r\n    margin-top: 0 !important;\r\n    margin-bottom: 0 !important;\r\n  }\r\n\r\n  .ts-breakout-inner {\r\n    width: 100% !important;\r\n    max-width: var(--ts-max) !important;\r\n    margin: 0 auto !important;\r\n    padding-left: var(--ts-pad) !important;\r\n    padding-right: var(--ts-pad) !important;\r\n    box-sizing: border-box !important;\r\n    font-family: inherit !important;\r\n  }\r\n\r\n  \/* -----------------------------------------------------------\r\n     3. BULLETPROOF WRAPPER (#toolSuiteWrap)\r\n  ----------------------------------------------------------- *\/\r\n\r\n  #toolSuiteWrap {\r\n    all: unset;\r\n    display: block;\r\n    box-sizing: border-box;\r\n    font-family: \"DM Sans\", \"Roboto\", \"Helvetica\", sans-serif;\r\n    color: var(--ts-text);\r\n    line-height: 1.5;\r\n    font-size: 16px;\r\n    font-weight: 400;\r\n    width: 100%;\r\n    overflow-x: hidden;\r\n  }\r\n  \r\n  #toolSuiteWrap * {\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  #toolSuiteWrap strong, \r\n  #toolSuiteWrap b {\r\n    font-weight: 700;\r\n  }\r\n\r\n  \/* Layout och Containrar *\/\r\n  #toolSuiteWrap #toolSuiteChooser,\r\n  #toolSuiteWrap #toolSuiteChooser * {\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  #toolSuiteWrap #tsCalcSeparator,\r\n  #toolSuiteWrap .ts-view {\r\n    width: 100% !important;\r\n    max-width: none !important;\r\n    box-sizing: border-box;\r\n  }\r\n\r\n  #toolSuiteWrap #toolSuiteChooser,\r\n  #toolSuiteWrap #tsCalcSeparator,\r\n  #toolSuiteWrap .ts-view,\r\n  #toolSuiteWrap .ts-card {\r\n    background: transparent !important;\r\n    border: 0 !important;\r\n    border-radius: 0 !important;\r\n    box-shadow: none !important;\r\n    padding: 0 !important;\r\n    margin: 0 !important;\r\n  }\r\n\r\n  #toolSuiteWrap .ts-rows,\r\n  #toolSuiteWrap .ts-rowline,\r\n  #toolSuiteWrap .ts-row-left,\r\n  #toolSuiteWrap .ts-row-right,\r\n  #toolSuiteWrap .ts-separator,\r\n  #toolSuiteWrap .ts-render {\r\n    width: 100% !important;\r\n    max-width: none !important;\r\n    display: block !important;\r\n  }\r\n\r\n  \/* Visa\/D\u00f6lj Logik *\/\r\n  #toolSuiteWrap .ts-render > .ts-view.ts-hidden {\r\n    display: none !important;\r\n  }\r\n  #toolSuiteWrap .ts-render > .ts-view:not(.ts-hidden) {\r\n    display: block !important;\r\n  }\r\n\r\n  #toolSuiteWrap [data-ts-mount=\"content\"] {\r\n    width: 100% !important;\r\n    max-width: none !important;\r\n    display: block !important;\r\n  }\r\n\r\n  \/* Inputs och Selects *\/\r\n  #toolSuiteWrap input,\r\n  #toolSuiteWrap select,\r\n  #toolSuiteWrap textarea {\r\n    color: var(--ts-text) !important;\r\n    opacity: 1 !important;\r\n    font-family: inherit !important;\r\n    font-size: 14px !important;\r\n    max-width: 100%;\r\n  }\r\n\r\n  #toolSuiteWrap select {\r\n    -webkit-appearance: none !important;\r\n    appearance: none !important;\r\n    background-color: #fff !important;\r\n    background-image: none !important;\r\n    padding-right: 24px !important;\r\n  }\r\n\r\n  #toolSuiteWrap input[type=\"checkbox\"] {\r\n    margin: 0 8px 0 0 !important;\r\n    flex: 0 0 auto !important;\r\n    width: auto !important;\r\n    display: inline-block !important;\r\n    appearance: checkbox !important;\r\n    -webkit-appearance: checkbox !important;\r\n  }\r\n\r\n  #toolSuiteWrap input[type=\"checkbox\"] + label,\r\n  #toolSuiteWrap label:has(input[type=\"checkbox\"]) {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 8px;\r\n    line-height: 1.2;\r\n    margin-bottom: 0 !important;\r\n  }\r\n\r\n  #toolSuiteWrap #viewPv label.sso-help {\r\n    display: flex !important;\r\n    align-items: center !important;\r\n    gap: 8px !important;\r\n    margin: 0 !important;\r\n    white-space: nowrap;\r\n    color: var(--ts-text) !important;\r\n  }\r\n\r\n  \/* -----------------------------------------------------------\r\n     KNAPPAR (STYLES H\u00c4R \u00c4R UPPDATERADE)\r\n  ----------------------------------------------------------- *\/\r\n  #toolSuiteWrap .ts-btn {\r\n    appearance: none;\r\n    -webkit-appearance: none;\r\n    border: 1px solid var(--fa-border) !important;\r\n    border-radius: 6px !important;\r\n    padding: 10px 16px !important;\r\n    font-size: 14px !important;\r\n    line-height: 1.1 !important;\r\n    cursor: pointer;\r\n    background: #fff !important; \/* Vit bakgrund som standard *\/\r\n    color: var(--ts-text) !important; \/* M\u00f6rk text som standard *\/\r\n    font-weight: 700 !important;\r\n    box-shadow: 0 1px 0 rgba(0, 0, 0, .08);\r\n    transition: all 0.2s ease; \/* Lite mjukare \u00f6verg\u00e5ng *\/\r\n    white-space: nowrap;\r\n    text-transform: none !important;\r\n    margin: 0 !important;\r\n  }\r\n\r\n  \/* HOVER-EFFEKT: Nu blir den gr\u00f6n med vit text *\/\r\n  #toolSuiteWrap .ts-btn:hover {\r\n    background-color: var(--fa-green) !important;\r\n    border-color: var(--fa-green) !important;\r\n    color: #fff !important;\r\n    box-shadow: 0 4px 6px rgba(0, 0, 0, .12); \/* Lite lyft *\/\r\n    transform: translateY(-1px);\r\n  }\r\n\r\n  \/* ACTIVE STATE: Redan gr\u00f6n *\/\r\n  #toolSuiteWrap .ts-btn.is-active {\r\n    background: var(--fa-green) !important;\r\n    border-color: var(--fa-green) !important;\r\n    color: #fff !important;\r\n  }\r\n\r\n  \/* ACTIVE HOVER: Lite m\u00f6rkare f\u00f6r att visa att man trycker *\/\r\n  #toolSuiteWrap .ts-btn.is-active:hover {\r\n    background: var(--fa-green-dark) !important;\r\n    border-color: var(--fa-green-dark) !important;\r\n    opacity: 0.95;\r\n  }\r\n\r\n  #toolSuiteWrap .ts-row-actions {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 10px;\r\n    width: 100% !important;\r\n  }\r\n\r\n  \/* SSO Submit Knappar *\/\r\n  #toolSuiteWrap .cc-submit {\r\n    appearance: none !important;\r\n    -webkit-appearance: none !important;\r\n    border: 1px solid var(--fa-border) !important;\r\n    border-radius: 6px !important;\r\n    padding: 10px 16px !important;\r\n    font-size: 14px !important;\r\n    font-weight: 700 !important;\r\n    cursor: pointer !important;\r\n    background: var(--fa-green) !important;\r\n    border-color: var(--fa-green) !important;\r\n    color: #fff !important;\r\n    box-shadow: 0 1px 0 rgba(0, 0, 0, .08) !important;\r\n    white-space: nowrap !important;\r\n    text-transform: none !important;\r\n    transition: all 0.2s ease !important;\r\n  }\r\n\r\n  #toolSuiteWrap .cc-submit:hover {\r\n    background: var(--fa-green-dark) !important;\r\n    border-color: var(--fa-green-dark) !important;\r\n    transform: translateY(-1px) !important;\r\n  }\r\n\r\n  #toolSuiteWrap #ssoExportButton {\r\n    position: relative !important;\r\n    padding-right: 44px !important;\r\n  }\r\n  \r\n  #toolSuiteWrap #ssoExportButton::after {\r\n    content: \"\u2192\" !important;\r\n    position: absolute !important;\r\n    right: 14px !important;\r\n    top: 50% !important;\r\n    transform: translateY(-50%) !important;\r\n    font-weight: 800 !important;\r\n    opacity: .95 !important;\r\n    color: #fff !important;\r\n  }\r\n\r\n  \/* Separatorer och Rubriker *\/\r\n  #toolSuiteWrap .ts-separator {\r\n    margin-top: 16px;\r\n    padding-top: 14px;\r\n    border-top: 1px solid rgba(0, 0, 0, .12);\r\n  }\r\n\r\n  #toolSuiteWrap .ts-sep-title {\r\n    margin: 0 0 10px;\r\n    font-weight: 700;\r\n    font-size: 14px;\r\n    color: var(--ts-text) !important;\r\n  }\r\n\r\n  #toolSuiteWrap .ts-section-kicker {\r\n    display: block !important;\r\n    text-align: center;\r\n    font-family: \"DM Mono\", monospace, sans-serif !important; \r\n    font-size: 16px !important;\r\n    font-weight: 400 !important;\r\n    text-transform: uppercase !important;\r\n    letter-spacing: 0.22em !important;\r\n    color: #A6AAA7 !important;\r\n    padding: 14px 16px;\r\n    background: transparent !important;\r\n  }\r\n\r\n  #toolSuiteWrap table, \r\n  #toolSuiteWrap th, \r\n  #toolSuiteWrap td {\r\n    border-collapse: collapse;\r\n    color: inherit;\r\n  }\r\n\r\n  \/* -----------------------------------------------------------\r\n     4. RESPONSIVITET (Mobile)\r\n  ----------------------------------------------------------- *\/\r\n  @media (max-width: 767px) {\r\n    #toolSuiteWrap .ts-btn {\r\n      width: 100%;\r\n    }\r\n    #toolSuiteWrap .ts-row-actions {\r\n      display: flex;\r\n      flex-direction: column;\r\n      gap: 10px;\r\n    }\r\n    \r\n    .ts-breakout-inner {\r\n      padding-left: 16px !important;\r\n      padding-right: 16px !important;\r\n    }\r\n\r\n    #toolSuiteWrap #ssoExportButton {\r\n      width: 100% !important;\r\n    }\r\n\r\n    #toolSuiteWrap table th,\r\n    #toolSuiteWrap table th * {\r\n      white-space: nowrap !important;\r\n    }\r\n\r\n    #toolSuiteWrap table th:nth-child(1),\r\n    #toolSuiteWrap table td:nth-child(1) {\r\n      width: 64px !important;\r\n      min-width: 64px !important;\r\n    }\r\n    #toolSuiteWrap table th:nth-child(2),\r\n    #toolSuiteWrap table td:nth-child(2) {\r\n      width: 92px !important;\r\n      min-width: 92px !important;\r\n    }\r\n    \r\n    #toolSuiteWrap table td:nth-child(3) {\r\n      white-space: normal !important;\r\n      word-break: break-word !important;\r\n    }\r\n\r\n    #toolSuiteWrap,\r\n    #toolSuiteWrap #viewSystem,\r\n    #toolSuiteWrap #viewPv,\r\n    #toolSuiteWrap #viewCable {\r\n      padding-left: 4px !important;\r\n      padding-right: 4px !important;\r\n    }\r\n    \r\n    #toolSuiteWrap .sso-layout,\r\n    #toolSuiteWrap .sso-form {\r\n      padding-left: 0 !important;\r\n      padding-right: 0 !important;\r\n      margin-left: 0 !important;\r\n      margin-right: 0 !important;\r\n      width: 100% !important;\r\n    }\r\n  }\r\n\r\n  #tsChooserAlert {\r\n    display: none !important;\r\n  }\r\n<\/style>\r\n\r\n<div class=\"ts-breakout\">\r\n  <div class=\"ts-breakout-inner\">\r\n    <div id=\"toolSuiteWrap\" class=\"ts-wrap\">\r\n      <section id=\"toolSuiteChooser\">\r\n\r\n        <div class=\"ts-rows\">\r\n          <div class=\"ts-section-kicker\">Dimensioning tool<\/div>\r\n          \r\n          <br>\r\n\r\n          <div class=\"ts-row-actions\">\r\n            <button\r\n              type=\"button\"\r\n              class=\"ts-btn ts-toggle\"\r\n              data-ts-go=\"system\"\r\n              data-ts-btn=\"system\"\r\n              aria-pressed=\"false\"\r\n            >\r\n              System calculator\r\n            <\/button>\r\n            \r\n            <button\r\n                type=\"button\"\r\n                class=\"ts-btn ts-toggle\"\r\n                data-ts-go=\"pv\"\r\n                data-ts-btn=\"pv\"\r\n                aria-pressed=\"false\"\r\n              >\r\n                SSO calculator\r\n            <\/button>\r\n\r\n            <button\r\n                type=\"button\"\r\n                class=\"ts-btn ts-toggle\"\r\n                data-ts-go=\"cable\"\r\n                data-ts-btn=\"cable\"\r\n                aria-pressed=\"false\"\r\n              >\r\n                Cable calculator\r\n            <\/button>\r\n          <\/div>\r\n\r\n          <br>\r\n        <\/div>\r\n\r\n        <div id=\"tsChooserAlert\" class=\"ts-alert ts-hidden\"><\/div>\r\n\r\n        <div class=\"ts-separator\" id=\"tsCalcSeparator\" style=\"display:none;\">\r\n          <div class=\"ts-sep-title\" id=\"tsActiveCalcTitle\"><\/div>\r\n\r\n          <div class=\"ts-render\">\r\n            <div id=\"viewSystem\" class=\"ts-view ts-hidden\">\r\n              <div data-ts-mount=\"header\"><\/div>\r\n              <div data-ts-mount=\"content\"><\/div>\r\n            <\/div>\r\n\r\n            <div id=\"viewPv\" class=\"ts-view ts-hidden\">\r\n              <div data-ts-mount=\"header\"><\/div>\r\n              <div data-ts-mount=\"content\"><\/div>\r\n            <\/div>\r\n\r\n            <div id=\"viewCable\" class=\"ts-view ts-hidden\">\r\n              <div data-ts-mount=\"header\"><\/div>\r\n              <div data-ts-mount=\"content\"><\/div>\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n      <\/section>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<script>\r\n(function () {\r\n  \"use strict\";\r\n\r\n  function qs(sel, root){ return (root || document).querySelector(sel); }\r\n  function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\r\n\r\n  var wrap = qs(\"#toolSuiteWrap\");\r\n  var chooser = qs(\"#toolSuiteChooser\");\r\n  var chooserAlert = qs(\"#tsChooserAlert\");\r\n  var separator = qs(\"#tsCalcSeparator\");\r\n  var activeTitle = qs(\"#tsActiveCalcTitle\");\r\n\r\n  if (!wrap || !chooser) return;\r\n\r\n  var views = {\r\n    system: qs(\"#viewSystem\"),\r\n    pv: qs(\"#viewPv\"),\r\n    cable: qs(\"#viewCable\")\r\n  };\r\n\r\n  var mounted = { system:false, pv:false, cable:false };\r\n\r\n  function keyLabel(key){\r\n    if (key === \"system\") return \"Systemkalkylator\";\r\n    if (key === \"pv\") return \"SSO kalkylator\";\r\n    if (key === \"cable\") return \"Kabelkalkylator\";\r\n    return \"\";\r\n  }\r\n\r\n  function hideChooserAlert(){\r\n    if (!chooserAlert) return;\r\n    chooserAlert.classList.add(\"ts-hidden\");\r\n    chooserAlert.textContent = \"\";\r\n  }\r\n\r\n  function moveNodeChildren(fromEl, toEl){\r\n    if (!fromEl || !toEl) return;\r\n    while (fromEl.firstChild) toEl.appendChild(fromEl.firstChild);\r\n  }\r\n\r\n  function forceHide(el){\r\n    if (!el) return;\r\n    el.classList.add(\"ts-hidden\");\r\n    el.style.setProperty(\"display\", \"none\", \"important\");\r\n  }\r\n\r\n  function forceShow(el){\r\n    if (!el) return;\r\n    el.classList.remove(\"ts-hidden\");\r\n    el.style.setProperty(\"display\", \"block\", \"important\");\r\n  }\r\n\r\n  function hideAllViews(){\r\n    Object.keys(views).forEach(function(k){\r\n      forceHide(views[k]);\r\n    });\r\n  }\r\n\r\n  function setActiveButton(activeKey){\r\n    qsa(\"[data-ts-btn]\", chooser).forEach(function (b) {\r\n      b.classList.remove(\"is-active\");\r\n      b.setAttribute(\"aria-pressed\", \"false\");\r\n    });\r\n    if (!activeKey) return;\r\n    var btn = qs('[data-ts-btn=\"' + activeKey + '\"]', chooser);\r\n    if (btn) {\r\n      btn.classList.add(\"is-active\");\r\n      btn.setAttribute(\"aria-pressed\", \"true\");\r\n    }\r\n  }\r\n\r\n  function showSeparator(){\r\n    if (!separator) return;\r\n    separator.style.display = \"\";\r\n    if (activeTitle) activeTitle.textContent = \"\";\r\n  }\r\n\r\n  function hideSeparator(){\r\n    if (!separator) return;\r\n    separator.style.display = \"none\";\r\n    if (activeTitle) activeTitle.textContent = \"\";\r\n  }\r\n\r\n  function setUrlTool(key){\r\n    try{\r\n      var url = new URL(window.location.href);\r\n      if (key) url.searchParams.set(\"tool\", key);\r\n      else url.searchParams.delete(\"tool\");\r\n      window.history.replaceState({}, \"\", url.toString());\r\n    }catch(e){}\r\n  }\r\n\r\n  function getUrlTool(){\r\n    try{\r\n      return ((new URL(window.location.href)).searchParams.get(\"tool\") || \"\").toLowerCase();\r\n    }catch(e){ return \"\"; }\r\n  }\r\n  \r\n  function lockScrollPosition() {\r\n    return {\r\n      x: window.pageXOffset || document.documentElement.scrollLeft || 0,\r\n      y: window.pageYOffset || document.documentElement.scrollTop || 0\r\n    };\r\n  }\r\n\r\n  function restoreScrollPosition(pos) {\r\n    if (!pos) return;\r\n    window.scrollTo(pos.x, pos.y);\r\n    requestAnimationFrame(function () {\r\n      window.scrollTo(pos.x, pos.y);\r\n      setTimeout(function () {\r\n        window.scrollTo(pos.x, pos.y);\r\n      }, 0);\r\n    });\r\n  }\r\n\r\n  function mountHeader(viewEl, key){\r\n    var host = qs('[data-ts-mount=\"header\"]', viewEl);\r\n    if (!host) return;\r\n    host.innerHTML = \"\";\r\n    var title = document.createElement(\"div\");\r\n    title.style.fontWeight = \"700\";\r\n    title.style.fontSize = \"16px\";\r\n    title.textContent = keyLabel(key);\r\n    host.appendChild(title);\r\n  }\r\n\r\n  function ensureMounted(key){\r\n    if (key === \"system\" && !mounted.system) {\r\n      var src0 = qs(\"#rootSystem\");\r\n      var dst0 = qs('[data-ts-mount=\"content\"]', views.system);\r\n      if (src0 && dst0) {\r\n        moveNodeChildren(src0, dst0);\r\n        mounted.system = true;\r\n        if (typeof window.initSystemCalculator === \"function\") window.initSystemCalculator();\r\n      }\r\n    }\r\n\r\n    if (key === \"pv\" && !mounted.pv) {\r\n      var src = qs(\"#rootPv\");\r\n      var dst = qs('[data-ts-mount=\"content\"]', views.pv);\r\n      if (src && dst) {\r\n        moveNodeChildren(src, dst);\r\n        mounted.pv = true;\r\n        if (typeof window.initSsoCalculator === \"function\") window.initSsoCalculator();\r\n      }\r\n    }\r\n\r\n    if (key === \"cable\" && !mounted.cable) {\r\n      var src2 = qs(\"#hiddenRootsCable #cableCalculatorRoot\") || qs(\"#cableCalculatorRoot\");\r\n      var dst2 = qs('[data-ts-mount=\"content\"]', views.cable);\r\n\r\n      if (dst2 && dst2.children && dst2.children.length > 0) {\r\n        mounted.cable = true;\r\n        return;\r\n      }\r\n\r\n      if (src2 && dst2) {\r\n        moveNodeChildren(src2, dst2);\r\n        mounted.cable = true;\r\n        if (typeof window.initCableCalculator === \"function\") {\r\n          setTimeout(function () {\r\n            window.initCableCalculator();\r\n          }, 0);\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  function showView(key){\r\n    var scrollPos = lockScrollPosition();\r\n    hideChooserAlert();\r\n    if (!views[key]) return;\r\n    ensureMounted(key);\r\n    hideAllViews();\r\n    setActiveButton(key);\r\n    showSeparator();\r\n\r\n    if (key !== \"cable\") {\r\n      mountHeader(views[key], key);\r\n    } else {\r\n      var h = qs('[data-ts-mount=\"header\"]', views[key]);\r\n      if (h) h.innerHTML = \"\";\r\n    }\r\n\r\n    forceShow(views[key]);\r\n    setUrlTool(key);\r\n    restoreScrollPosition(scrollPos);\r\n  }\r\n  \r\n  function clearAll(){\r\n    hideAllViews();\r\n    setActiveButton(\"\");\r\n    hideSeparator();\r\n    setUrlTool(\"\");\r\n    hideChooserAlert();\r\n  }\r\n\r\n  wrap.addEventListener(\"click\", function(e){\r\n    var btn = e.target && e.target.closest ? e.target.closest(\"[data-ts-go]\") : null;\r\n    if (!btn) return;\r\n    e.preventDefault();\r\n    var key = (btn.getAttribute(\"data-ts-go\") || \"\").toLowerCase();\r\n    if (!key) return;\r\n    showView(key);\r\n  });\r\n\r\n  clearAll();\r\n\r\n  var start = getUrlTool();\r\n  if (start && views[start]) showView(start);\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aa337d3 elementor-widget elementor-widget-dce-rawphp\" data-id=\"aa337d3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"dce-rawphp.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Dynamic PHP Raw -->\r\n<script>\r\n  window.toolSuiteData = window.toolSuiteData || {};\r\n\r\n  window.toolSuiteData.ssoPanels        = [{\"id\":\"0\",\"modell\":\"DMEGC 450 W FB - DM450M10RT-B54HBB\",\"pmax\":450,\"vmp\":33.24,\"voc\":39.8,\"imp\":13.54,\"isc\":14.04,\"voc_temp_coeff\":-0.25},{\"id\":\"1\",\"modell\":\"DMEGC 455 W FB - DM455G12RT-B48HBB\",\"pmax\":455,\"vmp\":34.11,\"voc\":40.45,\"imp\":13.34,\"isc\":14.24,\"voc_temp_coeff\":-0.25},{\"id\":\"2\",\"modell\":\"DMEGC 500 W FB - DM500M10RT-B60HBB\",\"pmax\":500,\"vmp\":37.66,\"voc\":44.7,\"imp\":13.3,\"isc\":14.22,\"voc_temp_coeff\":-0.25},{\"id\":\"3\",\"modell\":\"DMEGC 515W FB d.glas - DM515G12RT-G54HBB\",\"pmax\":515,\"vmp\":34.61,\"voc\":40.75,\"imp\":14.88,\"isc\":15.83,\"voc_temp_coeff\":-0.25},{\"id\":\"4\",\"modell\":\"DMEGC 465 W N helsv. - DM465G12RT-G48HBB\",\"pmax\":465,\"vmp\":31.21,\"voc\":36.46,\"imp\":14.91,\"isc\":15.88,\"voc_temp_coeff\":-0.25},{\"id\":\"5\",\"modell\":\"DMEGC 470 W N helsv. - DM470G12RT-G48HBB\",\"pmax\":470,\"vmp\":31.47,\"voc\":36.6,\"imp\":14.95,\"isc\":15.93,\"voc_temp_coeff\":-0.25},{\"id\":\"6\",\"modell\":\"HYUNDAI 435 W HG - HiE-S435HG(FB)\",\"pmax\":435,\"vmp\":36.2,\"voc\":43.6,\"imp\":12.02,\"isc\":12.79,\"voc_temp_coeff\":-0.27},{\"id\":\"7\",\"modell\":\"JA Solar 455 W - JAM54D41-455\\\/LB\",\"pmax\":455,\"vmp\":33.33,\"voc\":40.5,\"imp\":13.65,\"isc\":14.42,\"voc_temp_coeff\":-0.25},{\"id\":\"8\",\"modell\":\"JA Solar 500 W - JAM60D41-500\\\/LB\",\"pmax\":500,\"vmp\":38.26,\"voc\":45,\"imp\":13.07,\"isc\":14.05,\"voc_temp_coeff\":-0.25},{\"id\":\"9\",\"modell\":\"Leapton Solar 460 W - LP182*210-M-48-NB\",\"pmax\":460,\"vmp\":30.23,\"voc\":36.39,\"imp\":15.22,\"isc\":16.08,\"voc_temp_coeff\":-0.25},{\"id\":\"10\",\"modell\":\"Leapton Solar 510 W - LP182*210-M-54-NB\",\"pmax\":510,\"vmp\":33.73,\"voc\":40.57,\"imp\":15.12,\"isc\":16.01,\"voc_temp_coeff\":-0.25},{\"id\":\"11\",\"modell\":\"Leapton Solar 630 W - LP182*210-M-66-NB\",\"pmax\":630,\"vmp\":41.46,\"voc\":49.95,\"imp\":15.2,\"isc\":16.05,\"voc_temp_coeff\":-0.25},{\"id\":\"12\",\"modell\":\"Ledvance 590 W - M 590 N 72 LB -SF-F7\",\"pmax\":590,\"vmp\":42.92,\"voc\":51.88,\"imp\":13.75,\"isc\":14.48,\"voc_temp_coeff\":-0.26},{\"id\":\"13\",\"modell\":\"Longi 465 W Hi-MO X6-Max - LR7-54HTB\",\"pmax\":465,\"vmp\":33.54,\"voc\":39.71,\"imp\":13.8,\"isc\":14.77,\"voc_temp_coeff\":-0.23},{\"id\":\"14\",\"modell\":\"Sunpower 455 W FB d.glas - SPR-P7-455-BLK\",\"pmax\":455,\"vmp\":35.7,\"voc\":42.13,\"imp\":12.75,\"isc\":13.45,\"voc_temp_coeff\":-0.25},{\"id\":\"15\",\"modell\":\"Sunpower 510 W FB d.glas - SPR-P7-510-BLK-P\",\"pmax\":510,\"vmp\":39.69,\"voc\":47,\"imp\":12.85,\"isc\":13.56,\"voc_temp_coeff\":-0.25},{\"id\":\"16\",\"modell\":\"TCL solar 450 W d.glas tra. - HSM-ND48-GR450T\",\"pmax\":450,\"vmp\":30.13,\"voc\":35.56,\"imp\":14.94,\"isc\":16.06,\"voc_temp_coeff\":-0.25},{\"id\":\"17\",\"modell\":\"TCL solar 455 W FB d.glas - HSM-ND48-GR455\",\"pmax\":455,\"vmp\":30.32,\"voc\":35.76,\"imp\":15.01,\"isc\":16.13,\"voc_temp_coeff\":-0.25},{\"id\":\"18\",\"modell\":\"TCL solar 505 W FB d.glas - HSM-ND54-GR505\",\"pmax\":505,\"vmp\":33.9,\"voc\":40.14,\"imp\":14.9,\"isc\":15.88,\"voc_temp_coeff\":-0.25},{\"id\":\"19\",\"modell\":\"TCL solar 620 W d.glas - HSM-ND66-GR620\",\"pmax\":620,\"vmp\":40.98,\"voc\":48.94,\"imp\":14.13,\"isc\":16.05,\"voc_temp_coeff\":-0.25},{\"id\":\"20\",\"modell\":\"Trina 435 W - TSM-DE09R\",\"pmax\":435,\"vmp\":42.5,\"voc\":50.4,\"imp\":10.24,\"isc\":10.67,\"voc_temp_coeff\":-0.25},{\"id\":\"21\",\"modell\":\"Trina 440 W transparent - TSM-NEG9RC.27\",\"pmax\":440,\"vmp\":44,\"voc\":52.2,\"imp\":10.01,\"isc\":10.67,\"voc_temp_coeff\":-0.24},{\"id\":\"22\",\"modell\":\"Trina 450 W - TSM-NEG9R.28\",\"pmax\":450,\"vmp\":44.6,\"voc\":52.9,\"imp\":10.09,\"isc\":10.74,\"voc_temp_coeff\":-0.24},{\"id\":\"23\",\"modell\":\"Znshine Solar 380 W - ZXM6-NHLDD120\",\"pmax\":380,\"vmp\":34.6,\"voc\":41.2,\"imp\":10.91,\"isc\":11.43,\"voc_temp_coeff\":-0.29},{\"id\":\"24\",\"modell\":\"Znshine Solar 430 W - ZXM7-UHLDD108\",\"pmax\":430,\"vmp\":31.9,\"voc\":38.4,\"imp\":13.48,\"isc\":14.18,\"voc_temp_coeff\":-0.25},{\"id\":\"25\",\"modell\":\"Znshine Solar 480 W - ZXM7-UHLDD120\",\"pmax\":480,\"vmp\":35.5,\"voc\":42.8,\"imp\":13.53,\"isc\":14.31,\"voc_temp_coeff\":-0.25},{\"id\":\"26\",\"modell\":\"Leapton Solar 450 W - LP182*210-M-48-NB\",\"pmax\":450,\"vmp\":29.78,\"voc\":35.88,\"imp\":15.11,\"isc\":15.97,\"voc_temp_coeff\":-0.3},{\"id\":\"27\",\"modell\":\"Leapton Solar 500 W - LP182*210-M-54-NB\",\"pmax\":500,\"vmp\":33.33,\"voc\":40.07,\"imp\":15,\"isc\":15.9,\"voc_temp_coeff\":-0.3},{\"id\":\"28\",\"modell\":\"Leapton Solar 610 W - LP182*210-M-66-NB\",\"pmax\":610,\"vmp\":40.66,\"voc\":49.05,\"imp\":15,\"isc\":15.84,\"voc_temp_coeff\":-0.3}];\r\n  window.toolSuiteData.ssoLimits        = {\"sso2_voc\":1000,\"sso2_voc2\":720,\"sso2_vmp_low\":100,\"sso2_vmp_high\":720,\"sso2_isc_reduced\":13,\"sso2_imp_reduced\":12.5,\"sso2_imp_reduced2\":14,\"sso2_imp_reduced3\":16,\"sso2_imp_reduced_factor\":80};\r\n  window.toolSuiteData.sysconfProducts  = [{\"sysconf_artnr\":\"PH00205\",\"sysconf_enr\":\"5289206\",\"enr\":\"5289206\",\"name\":\"EnergyHub 14 kW\",\"max_power\":16.8},{\"sysconf_artnr\":\"PH01106\",\"sysconf_enr\":\"5289199\",\"enr\":\"5289199\",\"name\":\"EnergyHub Wall 21 kW\",\"max_power\":25.2},{\"sysconf_artnr\":\"PH01105\",\"sysconf_enr\":\"5289200\",\"enr\":\"5289200\",\"name\":\"EnergyHub Wall 28 kW\",\"max_power\":33.6},{\"sysconf_artnr\":\"PH01337\",\"sysconf_enr\":\"5289514\",\"enr\":\"5289514\",\"name\":\"EnergyHub Rack 24U ink XL 21 kW\",\"max_power\":25.2},{\"sysconf_artnr\":\"PH00798\",\"sysconf_enr\":\"5289205\",\"enr\":\"5289205\",\"name\":\"EnergyHub XL 21 kW\",\"max_power\":25.2},{\"sysconf_artnr\":\"PH01228\",\"sysconf_enr\":\"5289420\",\"enr\":\"5289420\",\"name\":\"EnergyHub Rack 24U ink XL 28kW\",\"max_power\":33.6},{\"sysconf_artnr\":\"PH01227\",\"sysconf_enr\":\"5289421\",\"enr\":\"5289421\",\"name\":\"EnergyHub Rack 42U ink XL 28kW\",\"max_power\":33.6},{\"sysconf_artnr\":\"PH00030\",\"sysconf_enr\":\"5289208\",\"enr\":\"5289208\",\"name\":\"EnergyHub XL 28 kW\",\"max_power\":33.6},{\"sysconf_artnr\":\"PB10011\",\"sysconf_enr\":\"2742064\",\"enr\":\"2742064\",\"name\":\"Pylontech Force H3 module\",\"max_power\":null},{\"sysconf_artnr\":\"PB10010\",\"sysconf_enr\":\"2742065\",\"enr\":\"2742065\",\"name\":\"Pylontech Force H3 controller\",\"max_power\":null},{\"sysconf_artnr\":\"PE00751\",\"sysconf_enr\":\"2740259\",\"enr\":\"2740259\",\"name\":\"ESO 6 kW\",\"max_power\":null},{\"sysconf_artnr\":\"PF10004\",\"sysconf_enr\":\"2740258\",\"enr\":\"2740258\",\"name\":\"PowerCase\",\"max_power\":null},{\"sysconf_artnr\":\"PS00990\",\"sysconf_enr\":\"5289195\",\"enr\":\"5289195\",\"name\":\"SSO 8 kW\",\"max_power\":null},{\"sysconf_artnr\":\"PS00778\",\"sysconf_enr\":\"5289181\",\"enr\":\"5289181\",\"name\":\"Power Distribution 5\",\"max_power\":null},{\"sysconf_artnr\":\"PS00779\",\"sysconf_enr\":\"5289180\",\"enr\":\"5289180\",\"name\":\"Power Distribution 8\",\"max_power\":null},{\"sysconf_artnr\":\"PS00772\",\"sysconf_enr\":\"5289182\",\"enr\":\"5289182\",\"name\":\"Power Distribution 15\",\"max_power\":null},{\"sysconf_artnr\":\"PE??????\",\"sysconf_enr\":\"52??????\",\"enr\":\"52??????\",\"name\":\"ESO 15 kW\",\"max_power\":null},{\"sysconf_artnr\":\"-\",\"sysconf_enr\":\"-\",\"enr\":\"-\",\"name\":\"Network switch minimum 4 ports\",\"max_power\":null}];\r\n  window.toolSuiteData.sysconfBatteries = [{\"id\":\"0\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":10.24,\"modules\":2,\"controllers\":1},{\"id\":\"1\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":15.36,\"modules\":3,\"controllers\":1},{\"id\":\"2\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":20.48,\"modules\":4,\"controllers\":1},{\"id\":\"3\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":25.6,\"modules\":5,\"controllers\":1},{\"id\":\"4\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":30.72,\"modules\":6,\"controllers\":1},{\"id\":\"5\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":35.84,\"modules\":7,\"controllers\":2},{\"id\":\"6\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":40.96,\"modules\":8,\"controllers\":2},{\"id\":\"7\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":46.08,\"modules\":9,\"controllers\":2},{\"id\":\"8\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":51.2,\"modules\":10,\"controllers\":2},{\"id\":\"9\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":56.32,\"modules\":11,\"controllers\":2},{\"id\":\"10\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":61.44,\"modules\":12,\"controllers\":2},{\"id\":\"11\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":66.56,\"modules\":13,\"controllers\":3},{\"id\":\"12\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":71.68,\"modules\":14,\"controllers\":3},{\"id\":\"13\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":76.8,\"modules\":15,\"controllers\":3},{\"id\":\"14\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":81.92,\"modules\":16,\"controllers\":3},{\"id\":\"15\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":87.04,\"modules\":17,\"controllers\":3},{\"id\":\"16\",\"name\":\"Pylontech Force H3\",\"energy_kwh\":92.16,\"modules\":18,\"controllers\":3}];\r\n\r\n  window.toolSuiteData.cableCables      = [];\r\n  window.toolSuiteData.cableInstalls    = [];\r\n  window.toolSuiteData.cableProfiles    = [];\r\n\r\n  window.ssoPanels        = window.toolSuiteData.ssoPanels;\r\n  window.ssoLimits        = window.toolSuiteData.ssoLimits;\r\n  window.sysconfProducts  = window.toolSuiteData.sysconfProducts;\r\n  window.sysconfBatteries = window.toolSuiteData.sysconfBatteries;\r\n<\/script>\r\n\r\n<section id=\"hiddenRoots\" style=\"display:none;\">\r\n\r\n  <div id=\"rootPv\">\r\n    <!-- L\u00e4gg in PV block h\u00e4r -->\r\n  <\/div>\r\n\r\n  <div id=\"rootSystem\">\r\n    <!-- L\u00e4gg in System block h\u00e4r -->\r\n  <\/div>\r\n\r\n  <div id=\"rootCable\">\r\n    <!-- L\u00e4gg in Cable block h\u00e4r -->\r\n  <\/div>\r\n\r\n<\/section>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cc59d10 elementor-widget elementor-widget-html\" data-id=\"cc59d10\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2canvas\/1.4.1\/html2canvas.min.js\"\r\n        crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\"><\/script>\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"\r\n        crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\"><\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-faae533 elementor-widget elementor-widget-html\" data-id=\"faae533\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =========================\r\nVIEW: SYSTEM (System calculator)\r\n========================= -->\r\n\r\n<section id=\"hiddenRootsSystem\" style=\"display:none;\">\r\n\r\n  <div id=\"systemCalculatorRoot\">\r\n    <section class=\"sso-calculator\" id=\"systemCalculator\">\r\n      <div class=\"sso-layout\">\r\n\r\n        <form id=\"sysconfCalculatorForm\" class=\"sso-form\">\r\n          <hr class=\"ps-summary-divider\">\r\n          <br>\r\n\r\n          <div class=\"sso-field-group\">\r\n            <div class=\"sso-label\"><strong>Panel configuration<\/strong><\/div>\r\n            <br>\r\n            <div class=\"sysconf-top-row\" style=\"display:flex;gap:12px;flex-wrap:wrap;\">\r\n              <div style=\"flex:1;min-width:140px;\">\r\n                <label class=\"sso-label\" for=\"sysconfNumPanels\">Number of panels<\/label>\r\n                <input id=\"sysconfNumPanels\" class=\"sso-input\" type=\"number\" min=\"1\" value=\"\" placeholder=\"Enter number...\">\r\n              <\/div>\r\n\r\n              <div style=\"flex:1;min-width:140px;\">\r\n                <label class=\"sso-label\" for=\"sysconfMountType\">Mounting<\/label>\r\n                <select id=\"sysconfMountType\" class=\"sso-input\">\r\n                  <option value=\"tak\">Roof mounting<\/option>\r\n                  <option value=\"mark\">Ground mounting<\/option>\r\n                  <option value=\"fasad\">Fa\u00e7ade mounting<\/option>\r\n                <\/select>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <input id=\"sysconfMinTemperature\" type=\"hidden\" value=\"-20\">\r\n          <input id=\"sysconfMaxTemperature\" type=\"hidden\" value=\"30\">\r\n          <br>\r\n\r\n          <div class=\"sso-field-group\">\r\n            <label class=\"sso-label\" for=\"sysconfPanelSelect\">Model<\/label>\r\n            <select id=\"sysconfPanelSelect\" class=\"sso-input\"><\/select>\r\n          <\/div>\r\n\r\n          <div id=\"sysconfManualModelGroup\" class=\"sso-field-group\" style=\"display:none\">\r\n            <br>\r\n            <label class=\"sso-label\" for=\"sysconfManualModel\">Solar panel name (optional)<\/label>\r\n            <input id=\"sysconfManualModel\" class=\"sso-input\" type=\"text\" placeholder=\"Enter model name...\">\r\n          <\/div>\r\n\r\n          <div id=\"sysconfPanelDataToggleWrap\" class=\"ts-hidden\" aria-hidden=\"true\" style=\"margin-top:6px\">\r\n            <button type=\"button\" id=\"sysconfPanelDataToggleBtn\" aria-expanded=\"false\" class=\"sso-toggle-row\">\r\n              <span data-paneldata-label>Show panel data<\/span>\r\n              <span data-paneldata-arrow aria-hidden=\"true\">\u25bc<\/span>\r\n            <\/button>\r\n          <\/div>\r\n\r\n          <div id=\"sysconfPanelDataGroup\" class=\"ts-hidden\" aria-hidden=\"true\" style=\"margin-top:12px;\">\r\n            <div class=\"sso-label\"><strong>Solar panel data<\/strong><\/div>\r\n            <br>\r\n\r\n            <div class=\"sso-panel-data-grid\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:12px 16px;\">\r\n              <div>\r\n                <label for=\"sysconfPanelPmax\">Pmax (W)<\/label>\r\n                <input id=\"sysconfPanelPmax\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n              <div>\r\n                <label for=\"sysconfPanelVmp\">Vmp (V)<\/label>\r\n                <input id=\"sysconfPanelVmp\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n              <div>\r\n                <label for=\"sysconfPanelVoc\">Voc (V)<\/label>\r\n                <input id=\"sysconfPanelVoc\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n              <div>\r\n                <label for=\"sysconfPanelImp\">Imp (A)<\/label>\r\n                <input id=\"sysconfPanelImp\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n              <div>\r\n                <label for=\"sysconfPanelIsc\">Isc (A)<\/label>\r\n                <input id=\"sysconfPanelIsc\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n              <div>\r\n                <label for=\"sysconfPanelVocCoeff\">Temp coeff Voc (%\/\u00b0C)<\/label>\r\n                <input id=\"sysconfPanelVocCoeff\" class=\"sso-input\" type=\"text\" readonly>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n          <br>\r\n\r\n          <div class=\"sso-field-group\" style=\"margin-top:18px;\">\r\n            <div class=\"sso-label\"><strong>Battery configuration<\/strong><\/div>\r\n            <br>\r\n            <div style=\"display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;\">\r\n              <div style=\"flex:2;min-width:180px;\">\r\n                <label class=\"sso-label\" for=\"sysconfBatterySelect\">Battery type<\/label>\r\n                <select id=\"sysconfBatterySelect\" class=\"sso-input\"><\/select>\r\n              <\/div>\r\n              <div style=\"flex:1;min-width:120px;\">\r\n                <label class=\"sso-label\" for=\"sysconfNumEso\">Battery power<\/label>\r\n                <select id=\"sysconfNumEso\" class=\"sso-input\"><\/select>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n        <\/form>\r\n\r\n        <!-- =========================\r\n          Cable calculator section (SYSTEM)\r\n        ========================= -->\r\n        <section class=\"ts-section\" id=\"tsCableSectionSystem\">\r\n          <div class=\"ts-card\">\r\n            <div class=\"ts-toggle-block\">\r\n              <div class=\"ts-toggle-head\">\r\n                <div class=\"ts-toggle-label\">Add cable calculation<\/div>\r\n\r\n                <label class=\"ts-switch\">\r\n                  <input type=\"checkbox\" class=\"ts-cable-toggle\" id=\"tsCableToggle\">\r\n                  <span class=\"ts-slider\" aria-hidden=\"true\"><\/span>\r\n                <\/label>\r\n              <\/div>\r\n\r\n              <div class=\"ts-expand ts-hidden ts-cable-expand\" aria-hidden=\"true\" style=\"margin-top:14px;\">\r\n\r\n                <div id=\"cableCalculatorRoot\">\r\n                  <section id=\"kabelkalkylatorPrint\" class=\"cable-calculator\">\r\n                    <div class=\"cc-layout\">\r\n\r\n                      <form id=\"cableCalculatorForm\" class=\"cc-form\">\r\n\r\n                        <div class=\"cc-mode-switch\" role=\"group\" aria-label=\"Cable type selection\">\r\n                          <button type=\"button\" id=\"modeBtnFromLoad\" class=\"cc-mode-btn is-active\" aria-pressed=\"true\">New cable<\/button>\r\n                          <button type=\"button\" id=\"modeBtnFromCable\" class=\"cc-mode-btn\" aria-pressed=\"false\">Existing cable<\/button>\r\n                        <\/div>\r\n\r\n                        <input class=\"cc-hidden-radio\" type=\"radio\" name=\"calc_mode\" id=\"modeFromLoad\" value=\"fromLoad\" checked>\r\n                        <input class=\"cc-hidden-radio\" type=\"radio\" name=\"calc_mode\" id=\"modeFromCable\" value=\"fromCable\">\r\n\r\n                        <h3 class=\"sso-section-title\">Cable A<\/h3>\r\n\r\n                        <div class=\"sso-field-group\">\r\n                          <label class=\"sso-label\" for=\"conductorConfigA\">Cable type<\/label>\r\n                          <select id=\"conductorConfigA\" name=\"conductor_config_a\" class=\"sso-input\">\r\n                            <option value=\"3\">3 conductors, L+, L-, PE<\/option>\r\n                            <option value=\"4\">4 conductors, L+, L-, X, PE<\/option>\r\n                            <option value=\"4_shield\">4 conductors with shield, 2xL+, 2xL-, PE = shield<\/option>\r\n                            <option value=\"5\">5 conductors, 2xL+, 2xL-, PE<\/option>\r\n                          <\/select>\r\n                        <\/div>\r\n\r\n                        <div class=\"sso-grid-3\">\r\n\r\n                          <div class=\"sso-field-group\" id=\"powerFieldA\">\r\n                            <label class=\"sso-label\" for=\"power\">Power<\/label>\r\n                            <div class=\"sso-unit\">\r\n                              <input id=\"power\" name=\"power_kw\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"e.g. 14\" value=\"\">\r\n                              <span class=\"sso-unit-text\">kW<\/span>\r\n                            <\/div>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\" id=\"knownCableFieldsA\" style=\"display:none;\">\r\n                            <label class=\"sso-label\" for=\"knownCableTypeA\">Cable cross-section<\/label>\r\n                            <select id=\"knownCableTypeA\" class=\"sso-input\"><\/select>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\">\r\n                            <label class=\"sso-label\" for=\"length\">Cable length<\/label>\r\n                            <div class=\"sso-unit\">\r\n                              <input id=\"length\" name=\"length_m\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"e.g. 10\" value=\"\">\r\n                              <span class=\"sso-unit-text\">m<\/span>\r\n                            <\/div>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\">\r\n                            <label class=\"sso-label\" for=\"maxDrop\">Max voltage drop<\/label>\r\n                            <div class=\"sso-unit\">\r\n                              <input id=\"maxDrop\" name=\"max_drop_percent\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"1\">\r\n                              <span class=\"sso-unit-text\">%<\/span>\r\n                            <\/div>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\">\r\n                            <label class=\"sso-label\" for=\"ambientTemp\">Ambient temperature<\/label>\r\n                            <div class=\"sso-unit\">\r\n                              <input id=\"ambientTemp\" name=\"ambient_temp_c\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"30\">\r\n                              <span class=\"sso-unit-text\">\u00b0C<\/span>\r\n                            <\/div>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\">\r\n                            <label class=\"sso-label\" for=\"installMethod\">Installation method<\/label>\r\n                            <select id=\"installMethod\" name=\"install_method\" class=\"sso-input\">\r\n                              <option value=\"A1\">A1, in wall, insulated<\/option>\r\n                              <option value=\"A2\">A2, in wall, uninsulated or lightly insulated<\/option>\r\n                              <option value=\"B1\">B1, in conduit in wall<\/option>\r\n                              <option value=\"C\" selected>C, on wall or in free air<\/option>\r\n                              <option value=\"D1\">D1, in ground, single cable<\/option>\r\n                              <option value=\"D2\">D2, in ground, multiple cables<\/option>\r\n                              <option value=\"E\">E, in conduit in ground<\/option>\r\n                            <\/select>\r\n                          <\/div>\r\n\r\n                          <div class=\"sso-field-group\">\r\n                            <label class=\"sso-label\" for=\"insulationType\">Cable insulation<\/label>\r\n                            <select id=\"insulationType\" name=\"insulation_type\" class=\"sso-input\">\r\n                              <option value=\"PVC70\">PVC 70 \u00b0C<\/option>\r\n                              <option value=\"XLPE90\">XLPE 90 \u00b0C<\/option>\r\n                            <\/select>\r\n                          <\/div>\r\n\r\n                        <\/div>\r\n\r\n                        <div class=\"cc-series-wrap\" style=\"margin:0.5rem 0;\">\r\n\r\n                          <div class=\"ts-toggle-block\">\r\n                            <div class=\"ts-toggle-head\">\r\n                              <div class=\"ts-toggle-label\">Add additional cable in series<\/div>\r\n\r\n                              <label class=\"ts-switch\">\r\n                                <input type=\"checkbox\" id=\"seriesToggle\">\r\n                                <span class=\"ts-slider\" aria-hidden=\"true\"><\/span>\r\n                              <\/label>\r\n                            <\/div>\r\n                          <\/div>\r\n\r\n                          <div id=\"seriesInputs\" data-series-inputs class=\"cc-series-inputs\" style=\"display:none;margin-top:0.5rem;padding-top:0.5rem;\">\r\n\r\n                            <h3 class=\"sso-section-title\" style=\"margin-top:0;\">Cable B<\/h3>\r\n\r\n                            <div class=\"sso-field-group\">\r\n                              <label class=\"sso-label\" for=\"conductorConfigB\">Cable type<\/label>\r\n                              <select id=\"conductorConfigB\" name=\"conductor_config_b\" class=\"sso-input\">\r\n                                <option value=\"3\">3 conductors, L+, L-, PE<\/option>\r\n                                <option value=\"4\">4 conductors, L+, L-, X, PE<\/option>\r\n                                <option value=\"4_shield\">4 conductors with shield, 2xL+, 2xL-, PE = shield<\/option>\r\n                                <option value=\"5\">5 conductors, 2xL+, 2xL-, PE<\/option>\r\n                              <\/select>\r\n                            <\/div>\r\n\r\n                            <div class=\"sso-grid-3\">\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"power2\">Power<\/label>\r\n                                <div class=\"sso-unit\">\r\n                                  <input id=\"power2\" name=\"power_kw2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"e.g. 8\" value=\"\">\r\n                                  <span class=\"sso-unit-text\">kW<\/span>\r\n                                <\/div>\r\n                              <\/div>\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"length2\">Cable length<\/label>\r\n                                <div class=\"sso-unit\">\r\n                                  <input id=\"length2\" name=\"length_m2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"e.g. 5\" value=\"\">\r\n                                  <span class=\"sso-unit-text\">m<\/span>\r\n                                <\/div>\r\n                              <\/div>\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"maxDrop2\">Max voltage drop<\/label>\r\n                                <div class=\"sso-unit\">\r\n                                  <input id=\"maxDrop2\" name=\"max_drop_percent2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"0.5\">\r\n                                  <span class=\"sso-unit-text\">%<\/span>\r\n                                <\/div>\r\n                              <\/div>\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"ambientTemp2\">Ambient temperature<\/label>\r\n                                <div class=\"sso-unit\">\r\n                                  <input id=\"ambientTemp2\" name=\"ambient_temp_c2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"30\">\r\n                                  <span class=\"sso-unit-text\">\u00b0C<\/span>\r\n                                <\/div>\r\n                              <\/div>\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"installMethod2\">Installation method<\/label>\r\n                                <select id=\"installMethod2\" name=\"install_method2\" class=\"sso-input\">\r\n                                  <option value=\"A1\">A1, in wall, insulated<\/option>\r\n                                  <option value=\"A2\">A2, in wall, uninsulated or lightly insulated<\/option>\r\n                                  <option value=\"B1\">B1, in conduit in wall<\/option>\r\n                                  <option value=\"C\" selected>C, on wall or in free air<\/option>\r\n                                  <option value=\"D1\">D1, in ground, single cable<\/option>\r\n                                  <option value=\"D2\">D2, in ground, multiple cables<\/option>\r\n                                  <option value=\"E\">E, in conduit in ground<\/option>\r\n                                <\/select>\r\n                              <\/div>\r\n\r\n                              <div class=\"sso-field-group\">\r\n                                <label class=\"sso-label\" for=\"insulationType2\">Cable insulation<\/label>\r\n                                <select id=\"insulationType2\" name=\"insulation_type2\" class=\"sso-input\">\r\n                                  <option value=\"PVC70\">PVC 70 \u00b0C<\/option>\r\n                                  <option value=\"XLPE90\">XLPE 90 \u00b0C<\/option>\r\n                                <\/select>\r\n                              <\/div>\r\n\r\n                            <\/div>\r\n\r\n                          <\/div>\r\n                        <\/div>\r\n\r\n                      <\/form>\r\n\r\n                      <section id=\"kabelkalkylatorPdf\" style=\"display:block; position:absolute; left:-99999px; top:0; min-height:1200px;\">\r\n                        <!-- Keep your existing PDF HTML here -->\r\n                      <\/section>\r\n\r\n                    <\/div>\r\n                  <\/section>\r\n                <\/div>\r\n\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n        <\/section>\r\n\r\n        <div class=\"sso-field-group\" style=\"margin-top:24px;\">\r\n          <button type=\"button\" id=\"sysconfCalcBtn\" class=\"cc-submit\">Run calculation<\/button>\r\n        <\/div>\r\n\r\n        <div id=\"sysconfCalcAlert\" style=\"display:none;margin-top:12px;border:1px solid #ffe1a6;background:#fff7e6;padding:10px 12px;border-radius:12px;font-size:13px;color:#5a3a00;\"><\/div>\r\n\r\n        <div id=\"sysconfAfterCalc\" style=\"display:none;\">\r\n          <br>\r\n          <hr class=\"ps-summary-divider\">\r\n          <aside id=\"sysconfResult\" class=\"sso-result\">\r\n            <h6><strong>System result<\/strong><\/h6>\r\n            <div id=\"sysconfResultLinesBox\" class=\"sso-result-lines\" style=\"margin-top:12px;\">\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">EnergyHub model<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResEnergyHubModel\"><\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\" id=\"sysconfRackModulesRow\" style=\"display:none;\">\r\n                <div class=\"sso-result-label\">Modules<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResRackModules\"><\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line sysconf-row-battery\">\r\n                <div class=\"sso-result-label\">Energy storage<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResBatterySummary\"><\/div>\r\n              <\/div>\r\n              <div id=\"sysconfSolarSeparator\" class=\"sysconf-solar-separator\" style=\"display:none;\"><\/div>\r\n              <div id=\"sysconfSolarBlock\" style=\"display:none;\">\r\n                <div class=\"sso-result-line\">\r\n                  <div class=\"sso-result-label\">Total panel power<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResInstalledPower\"><\/div>\r\n                <\/div>\r\n                <div class=\"sso-result-line\">\r\n                  <div class=\"sso-result-label\">Number of SSO single 8 kW<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResNumSso\"><\/div>\r\n                <\/div>\r\n                <div class=\"sso-result-line\">\r\n                  <div class=\"sso-result-label\">Min\/max number of panels per SSO<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResMinMaxPanelsPerSso\"><\/div>\r\n                <\/div>\r\n                <div id=\"sysconfDistributionLines\"><\/div>\r\n              <\/div>\r\n            <\/div>\r\n          <\/aside>\r\n\r\n          <br>\r\n\r\n          <div id=\"sysconfSolarTechToggleRow\" class=\"sysconf-tech-header\" style=\"display:none;\" aria-hidden=\"true\">\r\n            <button type=\"button\"\r\n                    id=\"sysconfSolarTechToggleBtn\"\r\n                    class=\"sso-toggle-row\"\r\n                    aria-expanded=\"false\"\r\n                    aria-controls=\"sysconfSolarTechCard\">\r\n              <span id=\"sysconfSolarTechToggleText\" class=\"sso-toggle-text\">Show technical details<\/span>\r\n              <span id=\"sysconfSolarTechToggleArrow\" class=\"sso-toggle-arrow\" aria-hidden=\"true\">\u25bc<\/span>\r\n            <\/button>\r\n          <\/div>\r\n\r\n          <div id=\"sysconfSolarTechCard\" class=\"ts-hidden\" aria-hidden=\"true\" style=\"margin-top:2px;\">\r\n            <div class=\"sso-result-lines sysconf-tech-lines\">\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Recommended string specification<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Vmp nominal<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResVmpNominal\">-<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Vmp min<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResVmpMin\">-<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Vmp max<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResVmpMax\">-<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Voc max<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResVocMax\">-<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Imp max<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResImp\">-<\/div>\r\n              <\/div>\r\n              <div class=\"sso-result-line\">\r\n                <div class=\"sso-result-label\">Isc<\/div>\r\n                <div class=\"sso-result-value\" id=\"sysconfResIsc\">-<\/div>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <br>\r\n          <hr class=\"ps-summary-divider\">\r\n\r\n          <h6><strong>Bill of materials<\/strong><\/h6>\r\n\r\n          <div class=\"sysconf-articles-card\">\r\n            <div class=\"sso-result-lines sysconf-articles-lines\">\r\n              <div class=\"sso-result-line sysconf-articles-head sysconf-articles-row\">\r\n                <div class=\"sysconf-col-qty\">Qty<\/div>\r\n                <div class=\"sysconf-col-enr\">Item no.<\/div>\r\n                <div class=\"sysconf-col-name\">Product name<\/div>\r\n              <\/div>\r\n              <div id=\"sysconfArticlesLines\"><\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <div id=\"sysconfCableCardWrap\" style=\"display:none; margin-top:16px;\">\r\n            <aside class=\"sso-result\">\r\n              <br>\r\n              <hr class=\"ps-summary-divider\">\r\n              <h6><strong>Cable calculation<\/strong><\/h6>\r\n\r\n              <div class=\"sso-result-lines\" style=\"margin-top:12px;\">\r\n                <div class=\"sso-result-line\" id=\"sysconfCableLineA\" style=\"display:none;\">\r\n                  <div class=\"sso-result-label\">Cable A<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResCableA\">-<\/div>\r\n                <\/div>\r\n                <div class=\"sso-result-line\" id=\"sysconfCableLineB\" style=\"display:none;\">\r\n                  <div class=\"sso-result-label\">Cable B<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResCableB\">-<\/div>\r\n                <\/div>\r\n                <div class=\"sso-result-line\" id=\"sysconfCableLineTotal\" style=\"display:none;\">\r\n                  <div class=\"sso-result-label\">Voltage drop<\/div>\r\n                  <div class=\"sso-result-value\" id=\"sysconfResCableTotal\">-<\/div>\r\n                <\/div>\r\n              <\/div>\r\n            <\/aside>\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n        <br>\r\n        <section id=\"sysconfPdfTemplate\" class=\"ts-hidden\" aria-hidden=\"true\">\r\n          <div class=\"tsPdfPage\" id=\"tsPdfPageSystem\">\r\n            <div class=\"tsPdfHeader\">\r\n              <div class=\"tsPdfHeaderLeft\">\r\n                <div class=\"tsPdfTitle\">System documentation<\/div>\r\n                <div class=\"tsPdfMeta\">\r\n                  <div class=\"tsPdfMetaRow\">\r\n                    <div class=\"tsPdfMetaLabel\">Project name<\/div>\r\n                    <div class=\"tsPdfMetaValue\" id=\"pdfProjectName\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfMetaRow\">\r\n                    <div class=\"tsPdfMetaLabel\">Date<\/div>\r\n                    <div class=\"tsPdfMetaValue\" id=\"pdfDate\">-<\/div>\r\n                  <\/div>\r\n                <\/div>\r\n              <\/div>\r\n              <div class=\"tsPdfBrand\">\r\n                <img decoding=\"async\"\r\n                  id=\"pdfBrandLogo\"\r\n                  src=\"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png.webp\"\r\n                  alt=\"Ferroamp\"\r\n                  crossorigin=\"anonymous\"\r\n                  style=\"height:28px; width:auto; display:block;\"\r\n                >\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfSection\" id=\"pdfSectionCore\" style=\"display:none;\">\r\n              <div class=\"tsPdfSectionTitle\">System<\/div>\r\n              <div class=\"tsPdfCard\">\r\n                <div class=\"tsPdfLine\" id=\"pdfHubRow\">\r\n                  <div class=\"tsPdfLabel\">EnergyHub<\/div>\r\n                  <div class=\"tsPdfValue\" id=\"pdfHubModel\">-<\/div>\r\n                <\/div>\r\n                <div class=\"tsPdfLine\" id=\"pdfRackModulesRow\" style=\"display:none;\">\r\n                  <div class=\"tsPdfLabel\">Modules<\/div>\r\n                  <div class=\"tsPdfValue\" id=\"pdfRackModules\">-<\/div>\r\n                <\/div>\r\n                <div class=\"tsPdfLine\" id=\"pdfBatteryRow\" style=\"display:none;\">\r\n                  <div class=\"tsPdfLabel\">Battery<\/div>\r\n                  <div class=\"tsPdfValue\" id=\"pdfBattery\">-<\/div>\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfSection\" id=\"pdfSectionArticles\" style=\"display:none;\">\r\n              <div class=\"tsPdfSectionTitle\">Bill of materials<\/div>\r\n              <div class=\"tsPdfCard tsPdfArticlesCard\">\r\n                <div class=\"tsPdfArticlesHead\">\r\n                  <div>Qty<\/div>\r\n                  <div>Item no.<\/div>\r\n                  <div>Product name<\/div>\r\n                <\/div>\r\n                <div class=\"tsPdfArticlesBody\" id=\"pdfArticlesBody\">\r\n                  <div id=\"pdfArticlesLines\"><\/div>\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfSection\" id=\"pdfSectionCable\" style=\"display:none;\">\r\n              <div class=\"tsPdfSectionTitle\">Cable calculation<\/div>\r\n              <div class=\"tsPdfGrid2Cards\">\r\n                <div class=\"tsPdfCard\">\r\n                  <div class=\"tsPdfCardTitle\">Calculation data<\/div>\r\n                  <div class=\"tsPdfSubTitleRow\">\r\n                    <div class=\"tsPdfSubTitle\" id=\"pdfCableNameA\">Cable A<\/div>\r\n                    <div class=\"tsPdfSubTitleValue\" id=\"pdfCableModeA\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLineCompact\">\r\n                    <div class=\"tsPdfLabel\">Power, length, max voltage drop<\/div>\r\n                    <div class=\"tsPdfValue\">\r\n                      <span id=\"pdfCablePowerA\">-<\/span>, <span id=\"pdfCableLengthA\">-<\/span>, <span id=\"pdfCableDropA\">-<\/span>\r\n                    <\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLineCompact\">\r\n                    <div class=\"tsPdfLabel\">Temperature, insulation<\/div>\r\n                    <div class=\"tsPdfValue\">\r\n                      <span id=\"pdfCableTempA\">-<\/span>, <span id=\"pdfCableInsulationA\">-<\/span>\r\n                    <\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLineCompact\">\r\n                    <div class=\"tsPdfLabel\">Installation method<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfCableInstallA\">-<\/div>\r\n                  <\/div>\r\n\r\n                  <div id=\"pdfCableInputsB\">\r\n                    <div class=\"tsPdfSubTitleRow\" id=\"pdfCableGroupTitleB\">\r\n                      <div class=\"tsPdfSubTitle\" id=\"pdfCableNameB\">Cable B<\/div>\r\n                      <div class=\"tsPdfSubTitleValue\" id=\"pdfCableModeB\">-<\/div>\r\n                    <\/div>\r\n                    <div class=\"tsPdfLineCompact\">\r\n                      <div class=\"tsPdfLabel\">Power, length, max voltage drop<\/div>\r\n                      <div class=\"tsPdfValue\">\r\n                        <span id=\"pdfCablePowerB\">-<\/span>, <span id=\"pdfCableLengthB\">-<\/span>, <span id=\"pdfCableDropB\">-<\/span>\r\n                      <\/div>\r\n                    <\/div>\r\n                    <div class=\"tsPdfLineCompact\">\r\n                      <div class=\"tsPdfLabel\">Temperature, insulation<\/div>\r\n                      <div class=\"tsPdfValue\">\r\n                        <span id=\"pdfCableTempB\">-<\/span>, <span id=\"pdfCableInsulationB\">-<\/span>\r\n                      <\/div>\r\n                    <\/div>\r\n                    <div class=\"tsPdfLineCompact\">\r\n                      <div class=\"tsPdfLabel\">Installation method<\/div>\r\n                      <div class=\"tsPdfValue\" id=\"pdfCableInstallB\">-<\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"tsPdfCard\">\r\n                  <div class=\"tsPdfCardTitle\">Cable result<\/div>\r\n                  <div class=\"tsPdfLineGroup\" id=\"pdfCableGroupA\">\r\n                    <div class=\"tsPdfLine\">\r\n                      <div class=\"tsPdfLabel\" id=\"pdfCableResultNameA\">Cable A<\/div>\r\n                      <div class=\"tsPdfValue\" id=\"pdfCableMaterialA\">-<\/div>\r\n                    <\/div>\r\n                    <div class=\"tsPdfLine tsPdfLineSub\">\r\n                      <div class=\"tsPdfLabel\">Conductor configuration<\/div>\r\n                      <div class=\"tsPdfValue\" id=\"pdfCableConfigA\">-<\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n\r\n                  <div class=\"tsPdfLineGroup\" id=\"pdfCableGroupB\">\r\n                    <div class=\"tsPdfLine\">\r\n                      <div class=\"tsPdfLabel\" id=\"pdfCableResultNameB\">Cable B<\/div>\r\n                      <div class=\"tsPdfValue\" id=\"pdfCableMaterialB\">-<\/div>\r\n                    <\/div>\r\n                    <div class=\"tsPdfLine tsPdfLineSub\">\r\n                      <div class=\"tsPdfLabel\">Conductor configuration<\/div>\r\n                      <div class=\"tsPdfValue\" id=\"pdfCableConfigB\">-<\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n\r\n                  <div class=\"tsPdfLine\" id=\"pdfCableLineTotal\">\r\n                    <div class=\"tsPdfLabel\">Voltage drop<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfCableTotal\">-<\/div>\r\n                  <\/div>\r\n\r\n                  <div class=\"tsPdfLine\" id=\"pdfCableLineSystemVoltage\">\r\n                    <div class=\"tsPdfLabel\">System voltage<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfSystemVoltage\">-<\/div>\r\n                  <\/div>\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfSection\" id=\"pdfSectionSolarTech\" style=\"display:none;\">\r\n              <div class=\"tsPdfSectionTitle\">SSO calculation<\/div>\r\n              <div class=\"tsPdfGrid2Cards\">\r\n                <div class=\"tsPdfCard\" id=\"pdfPanelInputCard\">\r\n                  <div class=\"tsPdfSubTitle\">Panel configuration<\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Panel model<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfPanelModel\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Quantity<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelCount\">-<\/span> pcs<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Mounting<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfMountType\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Temperature<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfMinTemp\">-<\/span> to <span id=\"pdfMaxTemp\">-<\/span> \u00b0C<\/div>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"tsPdfCard\" id=\"pdfPanelDataCard\">\r\n                  <div class=\"tsPdfSubTitle\">Panel data<\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Pmax<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelPmax\">-<\/span> W<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Vmp<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelVmp\">-<\/span> V<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Voc<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelVoc\">-<\/span> V<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Imp<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelImp\">-<\/span> A<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Isc<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelIsc\">-<\/span> A<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Voc coeff<\/div>\r\n                    <div class=\"tsPdfValue\"><span id=\"pdfPanelVocCoeff\">-<\/span> %<\/div>\r\n                  <\/div>\r\n                <\/div>\r\n              <\/div>\r\n\r\n              <div class=\"tsPdfGrid2Cards\" style=\"margin-top:24px;\">\r\n                <div class=\"tsPdfCard\" id=\"pdfSolarBlock\" style=\"display:none;\">\r\n                  <div class=\"tsPdfSubTitle\">Proposed string layout<\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Total panel power<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfSolarInstalled\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Number of SSO<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfNumSso\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Min\/max panels per SSO<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfMinMaxPanelsPerSso\">-<\/div>\r\n                  <\/div>\r\n                  <div id=\"pdfDistributionLines\" class=\"tsPdfDistribution\"><\/div>\r\n                <\/div>\r\n\r\n                <div class=\"tsPdfCard\" id=\"pdfTechBlock\" style=\"display:none;\">\r\n                  <div class=\"tsPdfSubTitle\">Recommended string specification<\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Vmp nominal<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfVmpNominal\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Vmp min<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfVmpMin\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Vmp max<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfVmpMax\">-<\/div>\r\n                  <\/div>\r\n                  <div class=\"tsPdfLine\">\r\n                    <div class=\"tsPdfLabel\">Voc max<\/div>\r\n                    <div class=\"tsPdfValue\" id=\"pdfVocMax\">-<\/div>\r\n                  <\/div>\r\n                <\/div>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfSection\" id=\"systemPdfSectionNotes\">\r\n              <div class=\"tsPdfNoteBox\" id=\"tsSystemPdfNoteBox\">\r\n                <div class=\"tsPdfNoteTitle\">Please note<\/div>\r\n                <ul class=\"tsPdfNoteList\" id=\"tsSystemPdfNoteList\">\r\n                  <li>The calculation is indicative and does not replace full system design.<\/li>\r\n                  <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\r\n                  <li>Panel calculations are based on the specified panel data. Bifacial gain is not included.<\/li>\r\n                  <li>Reverse polarity protection is inactive for panels with Isc above 13.5 A.<\/li>\r\n                  <li>Cable calculations are based on SS 436 40 00 and IEC 60364-5-52, with additional references to IEC 60228 and IEC 60269.<\/li>\r\n                  <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\r\n                <\/ul>\r\n              <\/div>\r\n            <\/div>\r\n\r\n          <\/div>\r\n        <\/section>\r\n\r\n        <section id=\"tsDocSectionSystem\">\r\n          <hr class=\"ps-summary-divider\">\r\n          <h6><strong>Documentation<\/strong><\/h6>\r\n\r\n          <div class=\"sso-field-group\" style=\"margin-top:12px;\">\r\n            <label class=\"sso-label\" for=\"tsProjectName\">Project name<\/label>\r\n            <input class=\"sso-input\" id=\"tsProjectName\" name=\"project_name\" type=\"text\" placeholder=\"Enter project name...\">\r\n          <\/div>\r\n\r\n          <div class=\"sso-field-group ts-hidden\" id=\"tsCableNameRowA\">\r\n            <label class=\"sso-label\" for=\"tsCableNameA\">Name for Cable A<\/label>\r\n            <input class=\"sso-input\" id=\"tsCableNameA\" name=\"cable_name_a\" type=\"text\" placeholder=\"Enter name for Cable A...\">\r\n          <\/div>\r\n\r\n          <div class=\"sso-field-group ts-hidden\" id=\"tsCableNameRowB\">\r\n            <label class=\"sso-label\" for=\"tsCableNameB\">Name for Cable B<\/label>\r\n            <input class=\"sso-input\" id=\"tsCableNameB\" name=\"cable_name_b\" type=\"text\" placeholder=\"Enter name for Cable B...\">\r\n          <\/div>\r\n\r\n          <div style=\"margin-top:14px;\">\r\n            <button type=\"button\" class=\"cc-submit\" id=\"tsCreatePdfBtn\">Create PDF<\/button>\r\n          <\/div>\r\n\r\n          <br>\r\n          <hr class=\"ps-summary-divider\">\r\n\r\n          <div class=\"sso-notes\">\r\n            <div class=\"sso-notes-title\">Please note<\/div>\r\n            <ul class=\"sso-notes-list\">\r\n              <li>The calculation is indicative and does not replace full system design.<\/li>\r\n              <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\r\n              <li>Panel calculations are based on the specified panel data. Bifacial gain is not included.<\/li>\r\n              <li>Reverse polarity protection is inactive for panels with Isc above 13.5 A.<\/li>\r\n              <li>Cable calculations are based on SS 436 40 00 and IEC 60364-5-52, with additional references to IEC 60228 and IEC 60269.<\/li>\r\n              <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\r\n            <\/ul>\r\n          <\/div>\r\n\r\n          <div id=\"tsSystemPdfHost\"\r\n               style=\"position:fixed; left:-10000px; top:0; width:794px; background:#fff; pointer-events:none; z-index:2147483647; opacity:1;\"><\/div>\r\n        <\/section>\r\n\r\n      <\/div>\r\n    <\/section>\r\n  <\/div>\r\n<\/section>\r\n\r\n\r\n\r\n\r\n<style>\r\n  :root{\r\n    --fa-green:#7fb52f;\r\n    --fa-green-dark:#9dc847;\r\n    --fa-border:#7fb52f;\r\n\r\n    --ts-text:#111;\r\n    --ts-muted:#666;\r\n\r\n    --ts-radius:14px;\r\n    --ts-pad:18px;\r\n\r\n    --field-radius:4px !important;\r\n    --field-min-h:46px;\r\n\r\n    \/* Standard *\/\r\n    --field-bg:#ffffff;\r\n    --field-shadow:0 0 0 1px rgba(0,0,0,0.04);\r\n    --field-focus-ring:0 0 0 3px rgba(127,181,47,0.25);\r\n\r\n    --tsPdfW:794px;\r\n    --tsPdfPadX:56px;\r\n    --tsPdfPadY:48px;\r\n  }\r\n\r\n  input[type=number]::-webkit-inner-spin-button,\r\n  input[type=number]::-webkit-outer-spin-button{\r\n    -webkit-appearance:none;\r\n    margin:0;\r\n  }\r\n  input[type=number]{ -moz-appearance:textfield; }\r\n\r\n  .ts-hidden{ display:none !important; }\r\n\r\n  \/* =========================================================\r\n     1) STOPPA PSEUDO-ELEMENT som ritar linjer (Elementor-container)\r\n     Du visade att en container hade ::after som kan rita linje.\r\n  ========================================================= *\/\r\n  .ts-toolsuite-container::before,\r\n  .ts-toolsuite-container::after,\r\n  .ts-toolsuite-container .elementor-container::before,\r\n  .ts-toolsuite-container .elementor-container::after,\r\n  .ts-toolsuite-container .elementor-widget-wrap::before,\r\n  .ts-toolsuite-container .elementor-widget-wrap::after,\r\n  .ts-toolsuite-container .elementor-widget-container::before,\r\n  .ts-toolsuite-container .elementor-widget-container::after{\r\n    content:none !important;\r\n    display:none !important;\r\n    border:0 !important;\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    background:transparent !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     2) WRAPPERS: nolla borders\/box-shadows\r\n  ========================================================= *\/\r\n  #systemCalculatorRoot .sso-field-group,\r\n  #systemCalculatorRoot .sysconf-top-row > div,\r\n  #systemCalculatorRoot .elementor-field-group,\r\n  #systemCalculatorRoot .elementor-field,\r\n  #systemCalculatorRoot .elementor-widget-container,\r\n  #systemCalculatorRoot .elementor-form-fields-wrapper,\r\n  #systemCalculatorRoot .elementor-field-subgroup,\r\n  #systemCalculatorRoot .elementor-field-type-text,\r\n  #systemCalculatorRoot .elementor-field-type-number,\r\n  #systemCalculatorRoot .elementor-field-type-select,\r\n  #systemCalculatorRoot .elementor-field-textual,\r\n  #systemCalculatorRoot .elementor-select-wrapper{\r\n    border:0 !important;\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    background:transparent !important;\r\n  }\r\n\r\n  #systemCalculatorRoot .sso-field-group::before,\r\n  #systemCalculatorRoot .sso-field-group::after,\r\n  #systemCalculatorRoot .sysconf-top-row > div::before,\r\n  #systemCalculatorRoot .sysconf-top-row > div::after,\r\n  #systemCalculatorRoot .elementor-field-group::before,\r\n  #systemCalculatorRoot .elementor-field-group::after,\r\n  #systemCalculatorRoot .elementor-field::before,\r\n  #systemCalculatorRoot .elementor-field::after,\r\n  #systemCalculatorRoot .elementor-widget-container::before,\r\n  #systemCalculatorRoot .elementor-widget-container::after,\r\n  #systemCalculatorRoot .elementor-form-fields-wrapper::before,\r\n  #systemCalculatorRoot .elementor-form-fields-wrapper::after,\r\n  #systemCalculatorRoot .elementor-field-textual::before,\r\n  #systemCalculatorRoot .elementor-field-textual::after,\r\n  #systemCalculatorRoot .elementor-select-wrapper::before,\r\n  #systemCalculatorRoot .elementor-select-wrapper::after{\r\n    content:none !important;\r\n    display:none !important;\r\n    border:0 !important;\r\n    box-shadow:none !important;\r\n    background:transparent !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     3) GLOBALA INPUT-REGLER (autoptimize\/theme) s\u00e4tter border.\r\n     H\u00e4r vinner vi genom h\u00f6gre specificitet + border-color transparent.\r\n  ========================================================= *\/\r\n  #systemCalculatorRoot input.sso-input,\r\n  #systemCalculatorRoot select.sso-input,\r\n  #systemCalculatorRoot textarea.sso-input{\r\n    border:0 !important;\r\n    border-color:transparent !important;\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    -webkit-box-shadow:none !important;\r\n    background-image:none !important;\r\n    filter:none !important;\r\n  }\r\n\r\n  \/* Extra h\u00e5rt mot typade inputs som ofta tr\u00e4ffas av globala selectors *\/\r\n  #systemCalculatorRoot input.sso-input[type=\"number\"],\r\n  #systemCalculatorRoot input.sso-input[type=\"text\"],\r\n  #systemCalculatorRoot input.sso-input[type=\"email\"],\r\n  #systemCalculatorRoot input.sso-input[type=\"tel\"],\r\n  #systemCalculatorRoot input.sso-input[type=\"url\"]{\r\n    border:0 !important;\r\n    border-color:transparent !important;\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    -webkit-box-shadow:none !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     4) Inputs\/selects: reset (\u00f6vriga)\r\n  ========================================================= *\/\r\n  #systemCalculatorRoot input,\r\n  #systemCalculatorRoot select,\r\n  #systemCalculatorRoot textarea,\r\n  #tsCableSectionSystem input,\r\n  #tsCableSectionSystem select,\r\n  #tsCableSectionSystem textarea{\r\n    -webkit-appearance:none !important;\r\n    appearance:none !important;\r\n\r\n    outline:0 !important;\r\n\r\n    background-image:none !important;\r\n    filter:none !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     5) SSO-input styling\r\n  ========================================================= *\/\r\n  #systemCalculatorRoot .sso-input,\r\n  #systemCalculatorRoot input.sso-input,\r\n  #systemCalculatorRoot select.sso-input,\r\n  #systemCalculatorRoot textarea.sso-input,\r\n  #tsCableSectionSystem .sso-input,\r\n  #tsCableSectionSystem input.sso-input,\r\n  #tsCableSectionSystem select.sso-input,\r\n  #tsCableSectionSystem textarea.sso-input{\r\n    width:100% !important;\r\n    min-height:var(--field-min-h) !important;\r\n\r\n    padding:12px 14px !important;\r\n\r\n    background:var(--field-bg) !important;\r\n    background-color:var(--field-bg) !important;\r\n\r\n    color:var(--ts-text) !important;\r\n\r\n    border:0 !important;\r\n    border-color:transparent !important;\r\n    outline:0 !important;\r\n\r\n    border-radius:var(--field-radius) !important;\r\n\r\n    box-shadow:var(--field-shadow) !important;\r\n    -webkit-box-shadow:var(--field-shadow) !important;\r\n\r\n    font-size:16px !important;\r\n    line-height:1.2 !important;\r\n\r\n    box-sizing:border-box !important;\r\n    background-clip:padding-box !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     6) FIX: Sysconf-toppen ska vara \"utan linje\"\r\n     Vi g\u00f6r den ljusgr\u00e5 och helt utan border\/box-shadow.\r\n     Kabeldelen p\u00e5verkas inte.\r\n  ========================================================= *\/\r\n  #systemCalculatorRoot #sysconfCalculatorForm .sso-input,\r\n  #systemCalculatorRoot #sysconfCalculatorForm input.sso-input,\r\n  #systemCalculatorRoot #sysconfCalculatorForm select.sso-input{\r\n    border:0 !important;\r\n    border-color:transparent !important;\r\n    outline:0 !important;\r\n\r\n    box-shadow:none !important;\r\n    -webkit-box-shadow:none !important;\r\n\r\n    background:#f3f5f6 !important;\r\n    background-color:#f3f5f6 !important;\r\n  }\r\n\r\n  \/* Extra h\u00e5rt riktat mot problemf\u00e4lten *\/\r\n  #systemCalculatorRoot #sysconfNumPanels,\r\n  #systemCalculatorRoot #sysconfMountType,\r\n  #systemCalculatorRoot #sysconfPanelSelect,\r\n  #systemCalculatorRoot #sysconfManualModel,\r\n  #systemCalculatorRoot #sysconfBatterySelect,\r\n  #systemCalculatorRoot #sysconfNumEso{\r\n    border:0 !important;\r\n    border-color:transparent !important;\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    -webkit-box-shadow:none !important;\r\n    background:#f3f5f6 !important;\r\n    background-color:#f3f5f6 !important;\r\n  }\r\n\r\n  \/* Placeholder *\/\r\n  #systemCalculatorRoot .sso-input::placeholder,\r\n  #tsCableSectionSystem .sso-input::placeholder{\r\n    color:rgba(0,0,0,0.45) !important;\r\n    opacity:1 !important;\r\n  }\r\n\r\n  \/* Focus *\/\r\n  #systemCalculatorRoot .sso-input:focus,\r\n  #tsCableSectionSystem .sso-input:focus{\r\n    outline:0 !important;\r\n    box-shadow:var(--field-shadow), var(--field-focus-ring) !important;\r\n    -webkit-box-shadow:var(--field-shadow), var(--field-focus-ring) !important;\r\n  }\r\n\r\n  \/* Sysconf focus: endast focus-ring *\/\r\n  #systemCalculatorRoot #sysconfCalculatorForm .sso-input:focus,\r\n  #systemCalculatorRoot #sysconfCalculatorForm input.sso-input:focus,\r\n  #systemCalculatorRoot #sysconfCalculatorForm select.sso-input:focus{\r\n    box-shadow:var(--field-focus-ring) !important;\r\n    -webkit-box-shadow:var(--field-focus-ring) !important;\r\n  }\r\n\r\n  \/* Readonly *\/\r\n  #systemCalculatorRoot .sso-input[readonly],\r\n  #tsCableSectionSystem .sso-input[readonly]{\r\n    background:#f6f7f7 !important;\r\n    background-color:#f6f7f7 !important;\r\n    color:rgba(0,0,0,0.75) !important;\r\n  }\r\n\r\n  \/* Select arrow *\/\r\n  #systemCalculatorRoot select.sso-input,\r\n  #tsCableSectionSystem select.sso-input{\r\n    padding-right:44px !important;\r\n    background-image:\r\n      linear-gradient(45deg, transparent 50%, rgba(0,0,0,0.55) 50%),\r\n      linear-gradient(135deg, rgba(0,0,0,0.55) 50%, transparent 50%) !important;\r\n    background-position:\r\n      calc(100% - 18px) 50%,\r\n      calc(100% - 12px) 50% !important;\r\n    background-size:6px 6px, 6px 6px !important;\r\n    background-repeat:no-repeat !important;\r\n  }\r\n  #systemCalculatorRoot select.sso-input::-ms-expand,\r\n  #tsCableSectionSystem select.sso-input::-ms-expand{\r\n    display:none !important;\r\n  }\r\n\r\n  .sso-unit{ display:flex; align-items:center; gap:10px; }\r\n  .sso-input-unit{ text-align:right; }\r\n  .sso-unit-text{ font-weight:400; color:var(--ts-text); white-space:nowrap; }\r\n\r\n  .ts-section{\r\n    width:100%;\r\n    box-sizing:border-box;\r\n    margin-top:18px;\r\n  }\r\n  .ts-card{\r\n    border:1px solid rgba(0,0,0,0.10);\r\n    border-radius:var(--ts-radius);\r\n    padding:var(--ts-pad);\r\n    background:#fff;\r\n    box-sizing:border-box;\r\n  }\r\n\r\n  #systemCalculatorRoot .sso-label,\r\n  #tsCableSectionSystem .sso-label{\r\n    display:block;\r\n    margin-bottom:8px;\r\n    font-weight:600;\r\n    color:var(--ts-text);\r\n  }\r\n\r\n  .ts-toggle-block{ padding:10px 0; }\r\n  .ts-toggle-head{ display:flex; align-items:center; gap:12px; }\r\n  .ts-toggle-label{ font-weight:700; color:var(--ts-text); line-height:1.2; }\r\n\r\n  .ts-switch{\r\n    position:relative;\r\n    width:38px;\r\n    height:20px;\r\n    flex:0 0 auto;\r\n  }\r\n  .ts-switch input{\r\n    position:absolute;\r\n    inset:0;\r\n    width:100%;\r\n    height:100%;\r\n    opacity:0;\r\n    margin:0;\r\n    cursor:pointer;\r\n  }\r\n  .ts-slider{\r\n    position:absolute;\r\n    inset:0;\r\n    background:#d9d9d9;\r\n    transition:0.18s;\r\n    border-radius:999px;\r\n    pointer-events:none;\r\n  }\r\n  .ts-slider:before{\r\n    content:\"\";\r\n    position:absolute;\r\n    height:14px;\r\n    width:14px;\r\n    left:3px;\r\n    top:3px;\r\n    background:#fff;\r\n    transition:0.18s;\r\n    border-radius:50%;\r\n    box-shadow:0 1px 2px rgba(0,0,0,0.20);\r\n  }\r\n  .ts-switch input:checked + .ts-slider{ background:var(--fa-green); }\r\n  .ts-switch input:checked + .ts-slider:before{ transform:translateX(18px); }\r\n\r\n  #sysconfPanelDataToggleBtn{\r\n    -webkit-appearance:none;\r\n    appearance:none;\r\n    background:transparent;\r\n    border:0;\r\n    box-shadow:none;\r\n    padding:0;\r\n    margin:0;\r\n    cursor:pointer;\r\n    display:inline-flex;\r\n    align-items:center;\r\n    gap:6px;\r\n    font:inherit;\r\n    color:#111;\r\n  }\r\n  #sysconfPanelDataToggleBtn:hover{ text-decoration:underline; }\r\n\r\n  #tsCableSectionSystem .sso-grid-3{\r\n    display:grid;\r\n    grid-template-columns:repeat(3, 1fr);\r\n    gap:12px 16px;\r\n    row-gap:16px !important;\r\n  }\r\n  @media (max-width:720px){\r\n    #tsCableSectionSystem .sso-grid-3{\r\n      grid-template-columns:1fr;\r\n      gap:12px;\r\n    }\r\n  }\r\n\r\n  #tsCableSectionSystem #kabelkalkylatorPrint .cc-mode-btn{\r\n    appearance:none;\r\n    -webkit-appearance:none;\r\n    border:1px solid var(--fa-border);\r\n    border-radius:6px;\r\n    padding:10px 16px;\r\n    font-size:14px;\r\n    line-height:1.1;\r\n    font-weight:400;\r\n    cursor:pointer;\r\n    background:#fff;\r\n    color:var(--ts-text);\r\n    box-sizing:border-box;\r\n    white-space:nowrap;\r\n    box-shadow:0 1px 0 rgba(0,0,0,0.08);\r\n    transition:160ms ease;\r\n  }\r\n  #tsCableSectionSystem #kabelkalkylatorPrint .cc-mode-btn.is-active{\r\n    background:var(--fa-green) !important;\r\n    border-color:var(--fa-green) !important;\r\n    color:#fff !important;\r\n  }\r\n\r\n\r\n\r\n  \/* PDF *\/\r\n  .tsPdfBrand img{\r\n    height:28px;\r\n    max-width:160px;\r\n    object-fit:contain;\r\n  }\r\n  #sysconfPdfTemplate #pdfBrandLogo{ visibility:visible !important; }\r\n\r\n  #sysconfPdfTemplate{\r\n    position:fixed !important;\r\n    left:-10000px !important;\r\n    top:0 !important;\r\n    width:var(--tsPdfW) !important;\r\n    visibility:hidden !important;\r\n    pointer-events:none !important;\r\n  }\r\n  #systemCalculatorRoot #sysconfPdfTemplate{ display:none !important; }\r\n\r\n  #tsSystemPdfHost{\r\n    width:var(--tsPdfW) !important;\r\n    max-width:var(--tsPdfW) !important;\r\n    background:#fff !important;\r\n    font-family:inherit !important;\r\n  }\r\n  #tsSystemPdfHost #sysconfPdfTemplate{\r\n    display:block !important;\r\n    position:static !important;\r\n    visibility:visible !important;\r\n  }\r\n\r\n  .tsPdfPage{\r\n    width:var(--tsPdfW) !important;\r\n    box-sizing:border-box !important;\r\n    padding:var(--tsPdfPadY) var(--tsPdfPadX) !important;\r\n    background:#fff !important;\r\n    color:var(--ts-text) !important;\r\n    overflow:hidden !important;\r\n  }\r\n\r\n  .tsPdfHeader{\r\n    display:flex;\r\n    justify-content:space-between;\r\n    align-items:flex-start;\r\n    margin-bottom:22px;\r\n  }\r\n  .tsPdfTitle{\r\n    font-size:26px;\r\n    font-weight:700;\r\n    line-height:1.15;\r\n  }\r\n\r\n  .tsPdfGrid2Cards{\r\n    display:grid;\r\n    grid-template-columns:1fr 1fr;\r\n    gap:16px;\r\n    width:100% !important;\r\n  }\r\n\r\n  .tsPdfCard{\r\n    border:1px solid #ededed;\r\n    border-radius:14px;\r\n    padding:12px 14px;\r\n    background:#fff;\r\n  }\r\n\r\n  .tsPdfLine{\r\n    display:flex;\r\n    justify-content:space-between;\r\n    gap:16px;\r\n    padding:7px 0;\r\n    border-bottom:1px solid #ededed;\r\n  }\r\n  .tsPdfLine:last-child{ border-bottom:0; }\r\n\r\n  .tsPdfArticlesHead{\r\n    display:grid;\r\n    grid-template-columns:10% 20% 70%;\r\n    gap:12px;\r\n    padding:10px 14px;\r\n    background:#fafafa;\r\n    border-bottom:1px solid #ededed;\r\n    font-size:11.8px;\r\n    font-weight:700;\r\n  }\r\n\r\n  .tsPdfArticlesRow{\r\n    display:grid;\r\n    grid-template-columns:10% 20% 70%;\r\n    gap:12px;\r\n    padding:8px 14px;\r\n    border-bottom:1px solid #ededed;\r\n    font-size:12.2px;\r\n  }\r\n\r\n  #tsSystemPdfHost .tsPdfNoteBox,\r\n  #sysconfPdfTemplate .tsPdfNoteBox{\r\n    padding:0;\r\n    background:transparent;\r\n    color:rgba(0,0,0,0.55);\r\n    font-size:11.5px;\r\n    line-height:1.35;\r\n  }\r\n\r\n  #tsSystemPdfHost .tsPdfNoteTitle,\r\n  #sysconfPdfTemplate .tsPdfNoteTitle{\r\n    font-weight:600;\r\n    color:rgba(0,0,0,0.70);\r\n    font-size:12px;\r\n    margin:0 0 4px 0;\r\n  }\r\n\r\n  #tsSystemPdfHost .tsPdfNoteList,\r\n  #sysconfPdfTemplate .tsPdfNoteList{\r\n    margin:0;\r\n    padding-left:14px;\r\n  }\r\n\r\n  #tsSystemPdfHost #systemPdfSectionNotes{ margin-top:36px; }\r\n\r\n  \/* Autoptimize global input\/select rule override, scoped to System Calculator *\/\r\n  #systemCalculatorRoot input.sso-input,\r\n  #systemCalculatorRoot select.sso-input,\r\n  #systemCalculatorRoot textarea.sso-input{\r\n    border:0 !important;\r\n    border-width:0 !important;\r\n    border-style:none !important;\r\n    border-color:transparent !important;\r\n\r\n    outline:0 !important;\r\n    box-shadow:none !important;\r\n    -webkit-box-shadow:none !important;\r\n\r\n    -webkit-appearance:none !important;\r\n    appearance:none !important;\r\n\r\n    background-image:none !important;\r\n  }\r\n\r\n  \/* Gemensam styling f\u00f6r ALLA ToolSuite-f\u00e4lt *\/\r\n  #systemCalculator .sso-input,\r\n  #kabelkalkylatorPrint .sso-input{\r\n    border:0 !important;\r\n    outline:0 !important;\r\n    border-radius:var(--field-radius) !important;\r\n    min-height:var(--field-min-h) !important;\r\n    padding:12px 14px !important;\r\n    box-shadow:var(--field-shadow) !important;\r\n    -webkit-box-shadow:var(--field-shadow) !important;\r\n    background:var(--field-bg) !important;\r\n    background-color:var(--field-bg) !important;\r\n  }\r\n\r\n  \/* Fokus *\/\r\n  #systemCalculator .sso-input:focus,\r\n  #kabelkalkylatorPrint .sso-input:focus{\r\n    box-shadow:var(--field-shadow), var(--field-focus-ring) !important;\r\n    -webkit-box-shadow:var(--field-shadow), var(--field-focus-ring) !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     Typografi: g\u00f6r kabeldelen identisk med paneldelen\r\n     L\u00e4gg detta sist i style-taggen\r\n  ========================================================= *\/\r\n\r\n  \/* Bastext i kabelsektionen *\/\r\n  #tsCableSectionSystem,\r\n  #tsCableSectionSystem *{\r\n    font-family:inherit !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Labels: samma som paneldelen *\/\r\n  #tsCableSectionSystem .sso-label{\r\n    display:block !important;\r\n    margin-bottom:8px !important;\r\n    font-weight:400 !important;\r\n    font-size:16px !important;\r\n    line-height:1.25 !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Om vissa labels i kabeldelen inte har .sso-label (ex label utan klass) *\/\r\n  #tsCableSectionSystem label{\r\n    font-weight:400 !important;\r\n    font-size:16px !important;\r\n    line-height:1.25 !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Rubriker som \"Kabel A\", \"Kabel B\" *\/\r\n  #tsCableSectionSystem .sso-section-title{\r\n    margin:14px 0 10px 0 !important;\r\n    font-size:16px !important;\r\n    font-weight:700 !important;\r\n    line-height:1.25 !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Hj\u00e4lptext \/ placeholder-lik text om n\u00e5got blir gr\u00e5tt i kabeldelen *\/\r\n  #tsCableSectionSystem .ts-muted,\r\n  #tsCableSectionSystem .sso-muted{\r\n    color:var(--ts-muted) !important;\r\n  }\r\n\r\n  \/* Enhetstext: kW, m, %, \u00b0C *\/\r\n  #tsCableSectionSystem .sso-unit-text{\r\n    font-weight:400 !important;\r\n    font-size:16px !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Mode-knappar: samma textk\u00e4nsla som resten (inte \"button-typografi\") *\/\r\n  #tsCableSectionSystem .cc-mode-btn{\r\n    font-family:inherit !important;\r\n    font-size:16px !important;\r\n    font-weight:700 !important;\r\n    line-height:1.1 !important;\r\n  }\r\n\r\n  \/* Dropdown pilar och select text ska matcha input text *\/\r\n  #tsCableSectionSystem select.sso-input,\r\n  #tsCableSectionSystem input.sso-input,\r\n  #tsCableSectionSystem textarea.sso-input{\r\n    font-family:inherit !important;\r\n    font-size:16px !important;\r\n    font-weight:400 !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Toggle-rad \"Ber\u00e4kna ytterligare kabel i serie\" *\/\r\n  #tsCableSectionSystem .ts-toggle-label{\r\n    font-weight:700 !important;\r\n    font-size:14px !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     Spacing paneldel: anv\u00e4nd r\u00e4tt scope (id=\"systemCalculator\")\r\n     L\u00e4gg detta SIST i style-taggen\r\n  ========================================================= *\/\r\n\r\n  \/* Field group spacing som kabeldelen *\/\r\n  #systemCalculator #sysconfCalculatorForm .sso-field-group{\r\n    margin:0 0 16px 0 !important;\r\n  }\r\n\r\n  \/* Label -> input avst\u00e5nd *\/\r\n  #systemCalculator #sysconfCalculatorForm .sso-label{\r\n    display:block !important;\r\n    margin:0 0 10px 0 !important;\r\n    line-height:1.25 !important;\r\n  }\r\n\r\n  \/* Om vissa labels saknar .sso-label i paneldata-grid *\/\r\n  #systemCalculator #sysconfCalculatorForm .sso-panel-data-grid label{\r\n    display:block !important;\r\n    margin:0 0 10px 0 !important;\r\n    line-height:1.25 !important;\r\n  }\r\n\r\n \r\n\r\n  \/* =========================================================\r\n     SYSTEM: Panel + Batteri input typography match Cable\r\n     L\u00e4gg detta ALLRA SIST i style-taggen\r\n  ========================================================= *\/\r\n\r\n  #systemCalculatorRoot #sysconfCalculatorForm input.sso-input,\r\n  #systemCalculatorRoot #sysconfCalculatorForm select.sso-input,\r\n  #systemCalculatorRoot #sysconfCalculatorForm textarea.sso-input{\r\n    font-family:inherit !important;\r\n    font-size:16px !important;\r\n    font-weight:400 !important;\r\n    line-height:1.2 !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Paneldata-grid labels kan ibland p\u00e5verka upplevd storlek *\/\r\n  #systemCalculatorRoot #sysconfCalculatorForm .sso-panel-data-grid label,\r\n  #systemCalculatorRoot #sysconfCalculatorForm .sso-label{\r\n    font-size:16px !important;\r\n    line-height:1.25 !important;\r\n  }\r\n\r\n\r\n\r\n  \/* =========================================================\r\n     SYSTEM: Panel + Batteri input font size fix\r\n     Matcha kabeldelens 16px\r\n  ========================================================= *\/\r\n  #systemCalculator #sysconfCalculatorForm input.sso-input,\r\n  #systemCalculator #sysconfCalculatorForm select.sso-input,\r\n  #systemCalculator #sysconfCalculatorForm textarea.sso-input{\r\n    font-size:16px !important;\r\n    font-weight:400 !important;\r\n    line-height:1.2 !important;\r\n    font-family:inherit !important;\r\n    color:var(--ts-text) !important;\r\n  }\r\n\r\n  \/* Placeholder ska ocks\u00e5 matcha *\/\r\n  #systemCalculator #sysconfCalculatorForm input.sso-input::placeholder{\r\n    font-size:16px !important;\r\n  }\r\n\r\n  \/* Tvinga Tech-toggle att ha samma stil som Paneldata-toggle *\/\r\n  #systemCalculator #sysconfSolarTechToggleBtn.sso-toggle-row,\r\n  #sysconfSolarTechToggleRow #sysconfSolarTechToggleBtn.sso-toggle-row{\r\n    border:0 !important;\r\n    background:transparent !important;\r\n    background-color:transparent !important;\r\n    background-image:none !important;\r\n    box-shadow:none !important;\r\n\r\n    color:var(--ts-text, #111) !important;\r\n    -webkit-text-fill-color:var(--ts-text, #111) !important;\r\n\r\n    font-size:16px;\r\n    line-height:24px;\r\n    font-weight:400;\r\n  }\r\n\r\n  #systemCalculator #sysconfSolarTechToggleBtn.sso-toggle-row:hover,\r\n  #sysconfSolarTechToggleRow #sysconfSolarTechToggleBtn.sso-toggle-row:hover{\r\n    border:0 !important;\r\n    background:transparent !important;\r\n    background-color:transparent !important;\r\n\r\n    color:var(--ts-text, #111) !important;\r\n    -webkit-text-fill-color:var(--ts-text, #111) !important;\r\n  }\r\n\r\n  \/* Neutralisera global theme button-style inom System Calculator *\/\r\n  #systemCalculator .sso-toggle-row{\r\n    border:0 !important;\r\n    background:transparent !important;\r\n    box-shadow:none !important;\r\n  }\r\n\r\n  \/* =========================================================\r\n     ARTIKELLISTA: (ENDA \u00e4ndringen i detta svar)\r\n     M\u00e5l: gr\u00e5 outer + vit inner-card utan extra \"dubbel inbuktning\"\r\n     Detta ers\u00e4tter dina tv\u00e5 tidigare dubbla artikellista-block\r\n  ========================================================= *\/\r\n\r\n  \/* Outer gr\u00e5 yta *\/\r\n  #systemCalculator .sysconf-articles-card{\r\n    background:#f3f5f6 !important;\r\n    border:1px solid rgba(0,0,0,0.06) !important;\r\n    border-radius:14px !important;\r\n    padding:18px !important;\r\n    box-sizing:border-box !important;\r\n  }\r\n\r\n  \/* Nolla eventuell padding\/margin som skapar extra inset *\/\r\n  #systemCalculator .sysconf-articles-card .sso-result-lines,\r\n  #systemCalculator .sysconf-articles-card .sysconf-articles-lines,\r\n  #systemCalculator .sysconf-articles-card #sysconfArticlesLines{\r\n    margin:0 !important;\r\n    padding:0 !important;\r\n    box-sizing:border-box !important;\r\n  }\r\n\r\n  \/* Inner vit tabell-card *\/\r\n  #systemCalculator .sysconf-articles-card .sysconf-articles-lines{\r\n    background:#fff !important;\r\n    border:1px solid rgba(0,0,0,0.08) !important;\r\n    border-radius:12px !important;\r\n    overflow:hidden !important;\r\n  }\r\n\r\n  \/* Header + rader *\/\r\n  #systemCalculator .sysconf-articles-card .sysconf-articles-row{\r\n    display:grid !important;\r\n    grid-template-columns:90px 140px 1fr !important;\r\n    align-items:center !important;\r\n    gap:0 !important;\r\n\r\n    padding:12px 16px !important;\r\n    box-sizing:border-box !important;\r\n\r\n    font-size:14px !important;\r\n    line-height:20px !important;\r\n    color:var(--ts-text, #111) !important;\r\n  }\r\n\r\n  \/* Header *\/\r\n  #systemCalculator .sysconf-articles-card .sysconf-articles-head.sysconf-articles-row{\r\n    background:#f6f7f7 !important;\r\n    font-weight:600 !important;\r\n    border-bottom:1px solid rgba(0,0,0,0.06) !important;\r\n  }\r\n\r\n  \/* Body rows *\/\r\n  #systemCalculator .sysconf-articles-card #sysconfArticlesLines .sysconf-articles-row{\r\n    background:#fff !important;\r\n    border-bottom:1px solid rgba(0,0,0,0.06) !important;\r\n  }\r\n\r\n  \/* Sista raden utan linje *\/\r\n  #systemCalculator .sysconf-articles-card #sysconfArticlesLines .sysconf-articles-row:last-child{\r\n    border-bottom:0 !important;\r\n  }\r\n\r\n  \/* Kolumnbeteende *\/\r\n  #systemCalculator .sysconf-articles-card .sysconf-col-qty,\r\n  #systemCalculator .sysconf-articles-card .sysconf-col-enr{\r\n    white-space:nowrap !important;\r\n  }\r\n\r\n  #systemCalculator .sysconf-articles-card .sysconf-col-name{\r\n    min-width:0 !important;\r\n  }\r\n\r\n  \/* Mobil *\/\r\n  @media (max-width:520px){\r\n    #systemCalculator .sysconf-articles-card{\r\n      padding:14px !important;\r\n    }\r\n    #systemCalculator .sysconf-articles-card .sysconf-articles-row{\r\n      grid-template-columns:70px 110px 1fr !important;\r\n      padding:10px 12px !important;\r\n    }\r\n  }\r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \/* =========================================================\r\n   ARTIKELLISTA: ta bort \"dubbel ruta\"\r\n   - Outer ska bara vara spacing (ingen border\/bakgrund)\r\n   - Inner ska vara enda rutan (border + radius)\r\n========================================================= *\/\r\n\r\n#systemCalculator .sysconf-articles-card{\r\n  background:transparent !important;\r\n  border:0 !important;\r\n  border-radius:0 !important;\r\n  padding:0 !important;                 \/* tar bort extra \"kort\" k\u00e4nslan *\/\r\n  box-shadow:none !important;\r\n}\r\n\r\n\/* SSO-result wrappern kan ibland ge egen padding\/ram *\/\r\n#systemCalculator .sysconf-articles-card .sso-result-lines{\r\n  background:transparent !important;\r\n  border:0 !important;\r\n  border-radius:0 !important;\r\n  padding:0 !important;\r\n  box-shadow:none !important;\r\n}\r\n\r\n\/* Enda synliga rutan *\/\r\n#systemCalculator .sysconf-articles-card .sysconf-articles-lines{\r\n  background:#fff !important;\r\n  border:1px solid rgba(0,0,0,0.08) !important;\r\n  border-radius:12px !important;\r\n  overflow:hidden !important;\r\n  box-shadow:none !important;\r\n}\r\n\r\n\/* Header + rader *\/\r\n#systemCalculator .sysconf-articles-card .sysconf-articles-row{\r\n  display:grid !important;\r\n  grid-template-columns:90px 140px 1fr !important;\r\n  align-items:center !important;\r\n  gap:0 !important;\r\n\r\n  padding:12px 16px !important;\r\n  box-sizing:border-box !important;\r\n\r\n  font-size:14px !important;\r\n  line-height:20px !important;\r\n  color:var(--ts-text, #111) !important;\r\n}\r\n\r\n\/* Header *\/\r\n#systemCalculator .sysconf-articles-card .sysconf-articles-head.sysconf-articles-row{\r\n  background:#f6f7f7 !important;\r\n  font-weight:600 !important;\r\n  border-bottom:1px solid rgba(0,0,0,0.06) !important;\r\n}\r\n\r\n\/* Body rows *\/\r\n#systemCalculator .sysconf-articles-card #sysconfArticlesLines .sysconf-articles-row{\r\n  background:#fff !important;\r\n  border-bottom:1px solid rgba(0,0,0,0.06) !important;\r\n}\r\n\r\n\/* Sista raden utan linje *\/\r\n#systemCalculator .sysconf-articles-card #sysconfArticlesLines .sysconf-articles-row:last-child{\r\n  border-bottom:0 !important;\r\n}\r\n\r\n\/* Kolumnbeteende *\/\r\n#systemCalculator .sysconf-articles-card .sysconf-col-qty,\r\n#systemCalculator .sysconf-articles-card .sysconf-col-enr{\r\n  white-space:nowrap !important;\r\n}\r\n\r\n#systemCalculator .sysconf-articles-card .sysconf-col-name{\r\n  min-width:0 !important;\r\n}\r\n\r\n\/* Mobil *\/\r\n@media (max-width:520px){\r\n  #systemCalculator .sysconf-articles-card .sysconf-articles-row{\r\n    grid-template-columns:70px 110px 1fr !important;\r\n    padding:10px 12px !important;\r\n  }\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\/* =========================================================\r\n   SYSTEM: Knappar ska se ut som \"Systemkalkylator\"\r\n   L\u00e4gg detta ALLRA SIST i style-taggen\r\n========================================================= *\/\r\n\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn{\r\n  -webkit-appearance:none !important;\r\n  appearance:none !important;\r\n\r\n  background:var(--fa-green) !important;\r\n  background-color:var(--fa-green) !important;\r\n  background-image:none !important;\r\n\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n\r\n  border:0 !important;\r\n  outline:0 !important;\r\n  box-shadow:none !important;\r\n\r\n  border-radius:999px !important; \/* pill-form som Systemkalkylator *\/\r\n  padding:14px 26px !important;   \/* mer \"systemkalkylator\"-kropp *\/\r\n\r\n  font:inherit !important;\r\n  font-weight:700 !important;\r\n  line-height:1.1 !important;\r\n\r\n  cursor:pointer !important;\r\n  text-decoration:none !important;\r\n\r\n  display:inline-flex !important;\r\n  align-items:center !important;\r\n  justify-content:center !important;\r\n}\r\n\r\n\/* Tvinga \u00e4ven ev child-element att bli vita *\/\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn *,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn *{\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n}\r\n\r\n\/* Hover, focus, active *\/\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn:hover,\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn:focus,\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn:focus-visible,\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn:active,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn:hover,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn:focus,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn:focus-visible,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn:active{\r\n  background:var(--fa-green-dark) !important;\r\n  background-color:var(--fa-green-dark) !important;\r\n\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n}\r\n\r\n\/* Disabled *\/\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn:disabled,\r\nhtml body #systemCalculatorRoot button#sysconfCalcBtn[disabled],\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn:disabled,\r\nhtml body #systemCalculatorRoot button#tsCreatePdfBtn[disabled]{\r\n  opacity:0.6 !important;\r\n  cursor:not-allowed !important;\r\n\r\n  background:var(--fa-green) !important;\r\n  background-color:var(--fa-green) !important;\r\n\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n}\r\n  \r\n  \r\n  \/* FIX: knappar ska ha vit text som Systemkalkylator *\/\r\nhtml body #systemCalculatorRoot #sysconfCalcBtn.cc-submit,\r\nhtml body #systemCalculatorRoot #tsCreatePdfBtn.cc-submit{\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n}\r\n\r\n\/* Safety: om tema l\u00e4gger span\/strong etc i knappen *\/\r\nhtml body #systemCalculatorRoot #sysconfCalcBtn.cc-submit *,\r\nhtml body #systemCalculatorRoot #tsCreatePdfBtn.cc-submit *{\r\n  color:#fff !important;\r\n  -webkit-text-fill-color:#fff !important;\r\n}\r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n\/* Bas: samma typsnitt\/grundstorlek i hela PDF:en *\/\r\n#tsSystemPdfHost,\r\n#tsSystemPdfHost * {\r\n  font-family: \"DM Sans\", \"Roboto\", \"Helvetica\", sans-serif !important;\r\n  color: #000 !important;\r\n  box-sizing: border-box !important;\r\n}\r\n\r\n\/* Sida + grundtextstorlek *\/\r\n#tsSystemPdfHost .tsPdfPage {\r\n  font-size: 11px !important;\r\n  line-height: 1.4 !important;\r\n}\r\n\r\n\/* Titel \"Systemdokumentation\" *\/\r\n#tsSystemPdfHost .tsPdfTitle {\r\n  font-size: 26px !important;\r\n  font-weight: 700 !important;\r\n  margin: 0 0 10px 0 !important;\r\n}\r\n\r\n\/* Projektnamn \/ Datum: tv\u00e5 rader, v\u00e4rdet h\u00f6gerst\u00e4lld *\/\r\n#tsSystemPdfHost .tsPdfMeta {\r\n  margin-top: 0 !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfMetaRow {\r\n  display: flex !important;\r\n  justify-content: space-between !important;\r\n  align-items: baseline !important;\r\n  gap: 32px !important;\r\n  font-size: 11px !important;\r\n  margin: 0 0 2px 0 !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfMetaLabel {\r\n  font-weight: 400 !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfMetaValue {\r\n  font-weight: 500 !important;\r\n  text-align: right !important;\r\n}\r\n\r\n\/* Sektionstitlar: \"System\", \"Artikellista\", \"SSO ber\u00e4kning\" *\/\r\n#tsSystemPdfHost .tsPdfSectionTitle {\r\n  font-size: 12px !important;\r\n  font-weight: 600 !important;\r\n  margin: 24px 0 8px 0 !important;\r\n}\r\n\r\n\/* Kort (System-rad, korten i SSO-ber\u00e4kning etc.) *\/\r\n#tsSystemPdfHost .tsPdfCard {\r\n  padding: 10px 14px !important;\r\n  border-radius: 14px !important;\r\n}\r\n\r\n\/* Vanliga rader i kort *\/\r\n#tsSystemPdfHost .tsPdfLine,\r\n#tsSystemPdfHost .tsPdfLineCompact {\r\n  font-size: 11px !important;\r\n  padding: 5px 0 !important;\r\n}\r\n\r\n\/* Etiketter vs v\u00e4rden inne i korten *\/\r\n#tsSystemPdfHost .tsPdfLine .tsPdfLabel,\r\n#tsSystemPdfHost .tsPdfLineCompact .tsPdfLabel {\r\n  font-weight: 400 !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfLine .tsPdfValue,\r\n#tsSystemPdfHost .tsPdfLineCompact .tsPdfValue {\r\n  font-weight: 500 !important;\r\n}\r\n\r\n\/* Artikellistan \u2013 huvud + rader lite fetare i v\u00e4rdedelen *\/\r\n#tsSystemPdfHost .tsPdfArticlesHead {\r\n  font-size: 11px !important;\r\n  font-weight: 600 !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfArticlesRow {\r\n  font-size: 11px !important;\r\n}\r\n\r\n#tsSystemPdfHost .tsPdfArticlesRow > div:nth-child(1),\r\n#tsSystemPdfHost .tsPdfArticlesRow > div:nth-child(2),\r\n#tsSystemPdfHost .tsPdfArticlesRow > div:nth-child(3) {\r\n  font-weight: 500 !important;\r\n}\r\n\r\n\/* Observera-text nederst *\/\r\n#tsSystemPdfHost .tsPdfNoteBox,\r\n#tsSystemPdfHost .tsPdfNoteBox li {\r\n  font-size: 10.5px !important;\r\n  line-height: 1.35 !important;\r\n}\r\n\r\n\/* SSO-\u00f6verrubriken \"SSO ber\u00e4kning\" *\/\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfSectionTitle {\r\n  font-size: 14px !important;\r\n  font-weight: 600 !important;\r\n  margin: 26px 0 10px 0 !important;\r\n}\r\n\r\n\/* Kort-rubriker p\u00e5 sida 2: \"Panelkonfiguration\", \"Paneldata\",\r\n   \"F\u00f6reslagen str\u00e4ngplanering\", \"Spec. f\u00f6r rek. panelstr\u00e4ng\" *\/\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfCard .tsPdfSubTitle {\r\n  font-size: 11.5px !important;\r\n  font-weight: 600 !important;\r\n  margin: 0 0 4px 0 !important;\r\n}\r\n\r\n\/* Rader inne i dessa kort \u2013 etikett normal, v\u00e4rde lite fetare *\/\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfLine .tsPdfLabel,\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfLineCompact .tsPdfLabel {\r\n  font-weight: 400 !important;\r\n}\r\n\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfLine .tsPdfValue,\r\n#tsSystemPdfHost #pdfSectionSolarTech .tsPdfLineCompact .tsPdfValue {\r\n  font-weight: 500 !important;\r\n}\r\n\r\n\/* Observera-rubrik *\/\r\n#tsSystemPdfHost #systemPdfSectionNotes .tsPdfNoteTitle {\r\n  font-size: 11.5px !important;\r\n  font-weight: 600 !important;\r\n  margin: 18px 0 4px 0 !important;\r\n  color: rgba(0, 0, 0, 0.70) !important;  \/* matchar m\u00f6rkare rubrikgr\u00e5 *\/\r\n}\r\n\r\n\/* Observera-listan \u2013 lite mindre och l\u00e4ttare text *\/\r\n#tsSystemPdfHost #systemPdfSectionNotes .tsPdfNoteList li {\r\n  font-size: 10.5px !important;\r\n  font-weight: 400 !important;\r\n  line-height: 1.4 !important;\r\n  margin: 0 0 2px 0 !important;\r\n  color: rgba(0, 0, 0, 0.55) !important;  \/* ljusare gr\u00e5 f\u00f6r br\u00f6dtexten *\/\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\/* ===== PDF: Cable section layout & typography ===== *\/\r\n\r\n\/* Sektionstitel \"Cable calculation\" *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSectionTitle {\r\n  font-size: 12px !important;\r\n  font-weight: 600 !important;\r\n  margin: 24px 0 8px 0 !important;\r\n}\r\n\r\n\/* Kort-rubriker: \"Calculation data\", \"Cable result\" *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfCardTitle {\r\n  font-size: 11.5px !important;\r\n  font-weight: 600 !important;\r\n  margin: 0 0 6px 0 !important;\r\n}\r\n\r\n\/* Sm\u00e5 underrubriker: \"Cable A\", \"Cable B\" *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSubTitle {\r\n  font-size: 11.5px !important;\r\n  font-weight: 400 !important;   \/* inte fet *\/\r\n}\r\n\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSubTitleValue {\r\n  font-size: 11.5px !important;\r\n  font-weight: 500 !important;   \/* \"New cable\" lite fetare till h\u00f6ger *\/\r\n}\r\n\r\n\/* Rader inne i kabelkorten: etiketter v\u00e4nster, v\u00e4rden h\u00f6ger *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLine,\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLineCompact {\r\n  display: flex !important;\r\n  justify-content: space-between !important;\r\n  align-items: baseline !important;\r\n  gap: 16px !important;\r\n  font-size: 11px !important;\r\n}\r\n\r\n\/* Etiketter (v\u00e4nster kolumn) \u2013 normal vikt *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLine .tsPdfLabel,\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLineCompact .tsPdfLabel {\r\n  font-weight: 400 !important;\r\n  text-align: left !important;\r\n}\r\n\r\n\/* V\u00e4rden (h\u00f6ger kolumn) \u2013 fetare + h\u00f6gerst\u00e4llda *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLine .tsPdfValue,\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLineCompact .tsPdfValue {\r\n  font-weight: 500 !important;\r\n  text-align: right !important;\r\n}\r\n\r\n\/* Rader i \"Cable result\"-kortet (material, konfiguration, total osv.) *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLineGroup .tsPdfLine .tsPdfLabel {\r\n  font-weight: 400 !important;\r\n}\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfLineGroup .tsPdfLine .tsPdfValue {\r\n  font-weight: 500 !important;\r\n  text-align: right !important;\r\n}\r\n\r\n\/* Cable A \/ Cable B header rows: value (\"New cable\") right-aligned *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSubTitleRow {\r\n  display: flex !important;\r\n  justify-content: space-between !important;\r\n  align-items: baseline !important;\r\n  gap: 16px !important;\r\n}\r\n\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSubTitle {\r\n  font-weight: 600 !important;\r\n  text-align: left !important;\r\n}\r\n\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfSubTitleValue {\r\n  font-weight: 500 !important;\r\n  text-align: right !important;\r\n}\r\n\r\n\/* PDF: lines between rows in left \"Calculation data\" card *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfGrid2Cards > .tsPdfCard:first-child .tsPdfLine,\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfGrid2Cards > .tsPdfCard:first-child .tsPdfLineCompact {\r\n  border-bottom: 1px solid #ededed;          \/* utan !important *\/\r\n}\r\n\r\n\/* Ingen linje p\u00e5 sista raden i v\u00e4nstra kortet *\/\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfGrid2Cards > .tsPdfCard:first-child .tsPdfLine:last-child,\r\n#tsSystemPdfHost #pdfSectionCable .tsPdfGrid2Cards > .tsPdfCard:first-child .tsPdfLineCompact:last-child {\r\n  border-bottom: 0 !important;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\/* Cable mode buttons: New cable \/ Existing cable *\/\r\n#tsCableSectionSystem .cc-mode-switch {\r\n  display: inline-flex;\r\n  gap: 8px;\r\n}\r\n\r\n#tsCableSectionSystem .cc-mode-btn {\r\n  -webkit-appearance: none !important;\r\n  appearance: none !important;\r\n  border-radius: 6px !important;    \/* pill *\/\r\n  padding: 10px 26px !important;       \/* mindre \u00e4n huvudknapparna *\/\r\n  border: 1px solid var(--fa-border) !important;\r\n  background: #fff !important;\r\n  color: #111 !important;\r\n\r\n  font-family: inherit !important;\r\n  font-size: 14px !important;         \/* lite mindre text *\/\r\n  font-weight: 700 !important;\r\n  line-height: 1.1 !important;\r\n\r\n  cursor: pointer !important;\r\n  box-shadow: none !important;\r\n  white-space: nowrap !important;\r\n}\r\n\r\n\/* Active state \u2013 gr\u00f6n som \u00f6vriga knappar, vit text *\/\r\n#tsCableSectionSystem .cc-mode-btn.is-active {\r\n  background: var(--fa-green) !important;\r\n  border-color: var(--fa-green) !important;\r\n  color: #fff !important;\r\n}\r\n\r\n\/* Optional: hover f\u00f6r inaktiva knappen *\/\r\n#tsCableSectionSystem .cc-mode-btn:not(.is-active):hover {\r\n  background: #7fb52f !important;\r\n  color: #fff !important;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\/* SYSTEM: neutralisera all gammal toggle-stil och anv\u00e4nd bara v\u00e5r *\/\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch,\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch::before,\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch::after {\r\n  position: relative;\r\n  width: 38px;\r\n  height: 20px;\r\n  flex: 0 0 auto;\r\n\r\n  padding: 0 !important;\r\n  margin: 0 !important;\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n  background: transparent !important;\r\n  content: none !important;\r\n}\r\n\r\n\/* D\u00f6lj native-checkboxen helt *\/\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch input[type=\"checkbox\"] {\r\n  appearance: none !important;\r\n  -webkit-appearance: none !important;\r\n  -moz-appearance: none !important;\r\n\r\n  position: absolute !important;\r\n  inset: 0 !important;\r\n  width: 100% !important;\r\n  height: 100% !important;\r\n\r\n  opacity: 0 !important;\r\n  margin: 0 !important;\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n  background: transparent !important;\r\n  cursor: pointer !important;\r\n}\r\n\r\n\/* Nolla ev. globala switch-stilar p\u00e5 span + pseudo-element *\/\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch input[type=\"checkbox\"] + .ts-slider,\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch input[type=\"checkbox\"] + .ts-slider::before,\r\n#systemCalculatorRoot #tsCableSectionSystem .ts-switch input[type=\"checkbox\"] + .ts-slider::after {\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n  background: transparent !important;\r\n}\r\n\r\n\/* SYSTEM: g\u00f6m \"gamla\" checkboxen f\u00f6r Add cable calculation\r\n   men l\u00e5t label + .ts-slider sk\u00f6ta togglingen *\/\r\n#systemCalculatorRoot #tsCableToggle,\r\n#systemCalculatorRoot input.ts-cable-toggle {\r\n  appearance: none !important;\r\n  -webkit-appearance: none !important;\r\n  -moz-appearance: none !important;\r\n\r\n  position: absolute !important;\r\n  inset: 0 !important;\r\n  width: 100% !important;\r\n  height: 100% !important;\r\n\r\n  opacity: 0 !important;              \/* osynlig *\/\r\n  margin: 0 !important;\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n  background: transparent !important;\r\n  cursor: pointer !important;\r\n}\r\n\r\n\r\n  \r\n<\/style>\r\n\r\n\r\n<script>\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n  \/\/ ===== Knappar (din befintliga kod) =====\r\n  var buttons = document.querySelectorAll('#sysconfCalcBtn, #tsCreatePdfBtn');\r\n\r\n  buttons.forEach(function (btn) {\r\n    btn.style.setProperty('background', '#7fb52f', 'important');\r\n    btn.style.setProperty('color', '#fff', 'important');\r\n    btn.style.setProperty('border', '0', 'important');\r\n    btn.style.setProperty('border-radius', '6px', 'important');\r\n    btn.style.setProperty('padding', '10px 26px', 'important');\r\n    btn.style.setProperty('font-weight', '700', 'important');\r\n    btn.style.setProperty('font-size', '14px', 'important');\r\n    btn.style.setProperty('line-height', '1.2', 'important');\r\n    btn.style.setProperty('display', 'inline-flex', 'important');\r\n    btn.style.setProperty('align-items', 'center', 'important');\r\n    btn.style.setProperty('justify-content', 'center', 'important');\r\n    btn.style.setProperty('text-decoration', 'none', 'important');\r\n\r\n    btn.addEventListener('mouseenter', function () {\r\n      btn.style.setProperty('background', '#9dc847', 'important'); \/\/ hover-f\u00e4rg\r\n    });\r\n\r\n    btn.addEventListener('mouseleave', function () {\r\n      btn.style.setProperty('background', '#7fb52f', 'important'); \/\/ grundf\u00e4rg\r\n    });\r\n  });\r\n\r\n  \/\/ ===== G\u00f6m \"gamla\" checkboxar bakom toggles =====\r\n  ['tsCableToggle', 'seriesToggle'].forEach(function (id) {\r\n    var t = document.getElementById(id);\r\n    if (!t) return;\r\n\r\n    t.style.setProperty('opacity', '0', 'important');\r\n    t.style.setProperty('background', 'transparent', 'important');\r\n    t.style.setProperty('border', '0', 'important');\r\n    t.style.setProperty('box-shadow', 'none', 'important');\r\n\r\n    t.style.setProperty('appearance', 'none', 'important');\r\n    t.style.setProperty('-webkit-appearance', 'none', 'important');\r\n    t.style.setProperty('-moz-appearance', 'none', 'important');\r\n  });\r\n});\r\n<\/script>\r\n\r\n\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2404989 elementor-widget elementor-widget-html\" data-id=\"2404989\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\n\/* =========================================================\n   System calculator + Cable calculator in one script\n   - Cable calculator is root-scoped to #kabelkalkylatorPrint\n   - System triggers cable via same \"Run calculation\" if enabled\n   - If any value changes a new calculation is required, also for cable parts\n========================================================= *\/\nwindow.initSystemCalculator = function () {\n  \"use strict\";\n\n  var data = window.toolSuiteData || {};\n  var panelsList  = Array.isArray(data.ssoPanels) ? data.ssoPanels : [];\n  var products    = Array.isArray(data.sysconfProducts) ? data.sysconfProducts : [];\n  var batteries   = Array.isArray(data.sysconfBatteries) ? data.sysconfBatteries : [];\n\n  function byId(id) { return document.getElementById(id); }\n\n  function toNumber(v) {\n    if (v === null || v === undefined) return NaN;\n    var n = parseFloat(String(v).trim().replace(\",\", \".\"));\n    return isNaN(n) ? NaN : n;\n  }\n  \nfunction updatePanelDataToggleVisibility() {\n  var toggleWrap = byId(\"sysconfPanelDataToggleWrap\");\n  var toggleRow  = byId(\"sysconfPanelDataToggleRow\");\n  var group      = byId(\"sysconfPanelDataGroup\");\n  if (!elPanelSelect || !toggleRow || !group) return;\n\n  var val = String(elPanelSelect.value || \"\");\n  var hasRealPanel = !!val && val !== \"manual\";\n\n  if (toggleWrap) {\n    toggleWrap.classList.toggle(\"ts-hidden\", !hasRealPanel);\n    toggleWrap.setAttribute(\"aria-hidden\", hasRealPanel ? \"false\" : \"true\");\n  } else {\n    toggleRow.classList.toggle(\"ts-hidden\", !hasRealPanel);\n  }\n\n  \/\/ Viktigt: vi r\u00f6r inte group h\u00e4r \u2013 det styrs i handlePanelSelectionChange\n}\n  \nfunction initPanelDataToggle() {\n  var panelSelect =\n    document.getElementById(\"sysconfPanelSelect\") ||\n    document.querySelector('select[name=\"sysconfPanelSelect\"]');\n\n  var toggleWrap = document.getElementById(\"sysconfPanelDataToggleWrap\");\n  var toggleBtn =\n    document.getElementById(\"sysconfPanelDataToggleBtn\") ||\n    document.querySelector(\"[data-paneldata-toggle]\");\n\n  var group =\n    document.getElementById(\"sysconfPanelDataGroup\") ||\n    document.querySelector(\"[data-paneldata-group]\");\n\n  if (!panelSelect || !toggleWrap || !toggleBtn || !group) return;\n  if (toggleBtn.__panelDataBound) return;\n  toggleBtn.__panelDataBound = true;\n\n  function updateToggleLabel(expanded) {\n    var labelEl = toggleBtn.querySelector(\"[data-paneldata-label]\");\n    var arrowEl = toggleBtn.querySelector(\"[data-paneldata-arrow]\");\n    if (labelEl) labelEl.textContent = expanded ? \"Hide panel data\" : \"Show panel data\";\n    if (arrowEl) arrowEl.textContent = expanded ? \"\u25b2\" : \"\u25bc\";\n    if (!labelEl && !arrowEl) toggleBtn.textContent = expanded ? \"Hide panel data \u25b2\" : \"Show panel data \u25bc\";\n  }\n\n  function setVisible(el, visible) {\n    if (!el) return;\n    el.style.display = visible ? \"\" : \"none\";\n    el.classList.toggle(\"ts-hidden\", !visible);\n    el.setAttribute(\"aria-hidden\", visible ? \"false\" : \"true\");\n  }\n\n  function setExpanded(expanded) {\n    toggleBtn.setAttribute(\"aria-expanded\", expanded ? \"true\" : \"false\");\n    setVisible(group, expanded);\n    updateToggleLabel(expanded);\n  }\n\n  function hasPanelSelected() {\n    var val = String(panelSelect.value || \"\").trim();\n    return !!val && val !== \"manual\";\n  }\n\n  function refresh() {\n    var ok = hasPanelSelected();\n    setVisible(toggleWrap, ok);\n    if (!ok) {\n      setExpanded(false);\n      return;\n    }\n    setExpanded(false);\n  }\n\n  toggleBtn.setAttribute(\"aria-expanded\", \"false\");\n  updateToggleLabel(false);\n  setVisible(group, false);\n\n  toggleBtn.addEventListener(\"click\", function () {\n    var isExpanded = toggleBtn.getAttribute(\"aria-expanded\") === \"true\";\n    setExpanded(!isExpanded);\n  });\n\n  panelSelect.addEventListener(\"change\", refresh);\n\n  refresh();\n  setTimeout(refresh, 0);\n}\n\n\n\n\n\n  function formatNumber(n, decimals) {\n    if (!isFinite(n)) return \"-\";\n    return n.toLocaleString(\"sv-SE\", {\n      minimumFractionDigits: decimals,\n      maximumFractionDigits: decimals\n    });\n  }\n\n  function scrollToElement(el, offset) {\n    if (!el) return;\n    var y = el.getBoundingClientRect().top + window.pageYOffset + (offset || 0);\n    window.scrollTo({ top: y, behavior: \"smooth\" });\n  }\n\n  function setElDisplay(el, show) {\n    if (!el) return;\n    el.style.display = show ? \"\" : \"none\";\n  }\n\n  function setTextSafe(el, txt) {\n    if (!el) return;\n    el.textContent = (txt == null || txt === \"\") ? \"-\" : String(txt);\n  }\n  \nfunction initSolarTechToggle() {\n  var btn = document.getElementById(\"sysconfSolarTechToggleBtn\");\n  var card = document.getElementById(\"sysconfSolarTechCard\");\n  var text = document.getElementById(\"sysconfSolarTechToggleText\");\n  var arrow = document.getElementById(\"sysconfSolarTechToggleArrow\");\n\n  if (!btn || !card || !text) return;\n\n  function setOpen(isOpen) {\n    btn.setAttribute(\"aria-expanded\", isOpen ? \"true\" : \"false\");\n    card.setAttribute(\"aria-hidden\", isOpen ? \"false\" : \"true\");\n    card.classList.toggle(\"ts-hidden\", !isOpen);\n    text.textContent = isOpen ? \"Hide technical details\" : \"Show technical details\";\n\n    if (arrow) arrow.style.transform = isOpen ? \"rotate(180deg)\" : \"rotate(0deg)\";\n  }\n\n  if (!btn.__boundTechToggle) {\n    btn.__boundTechToggle = true;\n    btn.addEventListener(\"click\", function () {\n      var isOpen = btn.getAttribute(\"aria-expanded\") === \"true\";\n      setOpen(!isOpen);\n    });\n  }\n\n  setOpen(false);\n}\n\n\n\n  \/* =========================================================\n     Cable calculator module\n  ========================================================= *\/\n  var cableModule = (function createCableModule() {\n    var defaultsApplied = false;\n    var module = {};\n    var root = null;\n    var uiSyncing = false;\n\n    module.onDirty = null;\n    \n    function setCableError(code, message) {\n  window.__cableLastError = {\n    code: code || \"unknown\",\n    message: message || \"\"\n  };\n}\n\n    function getCableRootElement() {\n      var scoped = document.querySelector(\"#tsCableSectionSystem #kabelkalkylatorPrint\");\n      if (scoped) return scoped;\n      return document.getElementById(\"kabelkalkylatorPrint\");\n    }\n\n    function inRoot(id) {\n      return root ? root.querySelector(\"#\" + id) : null;\n    }\n\n    function setText(id, txt) {\n      var el = inRoot(id);\n      if (!el) return;\n      el.textContent = (txt == null || txt === \"\") ? \"-\" : String(txt);\n    }\n\n    function styleToggleButton(button, active) {\n      if (!button) return;\n      button.classList.toggle(\"is-active\", !!active);\n      button.setAttribute(\"aria-pressed\", active ? \"true\" : \"false\");\n    }\n\n    function setBlockVisible(block, visible) {\n      if (!block) return;\n\n      block.style.display = visible ? \"\" : \"none\";\n\n      if (visible) block.removeAttribute(\"hidden\");\n      else block.setAttribute(\"hidden\", \"hidden\");\n\n      if (block.classList) {\n        if (visible) {\n          block.classList.remove(\"ts-hidden\");\n          block.classList.remove(\"cc-hidden\");\n          block.classList.remove(\"hidden\");\n        } else {\n          block.classList.add(\"ts-hidden\");\n        }\n      }\n    }\n\n    function getSeriesInputsEl() {\n      if (!root) return null;\n\n      var power2 = inRoot(\"power2\");\n      if (power2) {\n        return (\n          power2.closest(\"[data-series-inputs]\") ||\n          power2.closest(\".cc-series-inputs\") ||\n          power2.closest(\".series-inputs\") ||\n          power2.closest(\"#seriesInputs\") ||\n          power2.closest(\".cc-series-wrap\")\n        );\n      }\n\n      return (\n        inRoot(\"seriesInputs\") ||\n        root.querySelector('[data-series-inputs]') ||\n        root.querySelector(\".cc-series-inputs\") ||\n        root.querySelector(\"#seriesInputs\")\n      );\n    }\n\n    function getSeriesResultEl() {\n      return inRoot(\"seriesResult\")\n        || (root ? root.querySelector('[data-series-result]') : null)\n        || (root ? root.querySelector(\".cc-series-result\") : null);\n    }\n\n    function forceSeriesInputsVisibility(on) {\n      if (!root) return;\n\n      var seriesInputs = inRoot(\"seriesInputs\");\n      var seriesWrapper = getSeriesInputsEl();\n\n      function showBlock(el, visible) {\n        if (!el) return;\n\n        el.style.display = visible ? \"\" : \"none\";\n\n        if (visible) el.removeAttribute(\"hidden\");\n        else el.setAttribute(\"hidden\", \"hidden\");\n\n        if (el.classList) {\n          if (visible) {\n            el.classList.remove(\"ts-hidden\");\n            el.classList.remove(\"cc-hidden\");\n            el.classList.remove(\"hidden\");\n          } else {\n            el.classList.add(\"ts-hidden\");\n          }\n        }\n      }\n\n      showBlock(seriesWrapper, !!on);\n      showBlock(seriesInputs, !!on);\n\n      if (seriesInputs && !!on) {\n        seriesInputs.style.display = \"block\";\n      }\n    }\n\n    function findBlockForInput(inputEl) {\n      if (!inputEl) return null;\n      return (\n        inputEl.closest(\"[data-cc-block]\") ||\n        inputEl.closest(\".cc-field\") ||\n        inputEl.closest(\".cc-row\") ||\n        inputEl.closest(\".cc-block\") ||\n        inputEl.parentElement\n      );\n    }\n\n    function applySeriesState(on) {\n      uiSyncing = true;\n      try {\n        var chk = inRoot(\"seriesToggle\");\n        if (chk) chk.checked = !!on;\n\n        var seriesResult = getSeriesResultEl();\n        if (seriesResult) seriesResult.style.display = \"none\";\n\n        function setFieldVisibleById(id, visible) {\n          var el = inRoot(id);\n          if (!el) return;\n          var block = findBlockForInput(el);\n          setBlockVisible(block, visible);\n        }\n\n        var seriesInputsWrapper = getSeriesInputsEl();\n        if (seriesInputsWrapper) setBlockVisible(seriesInputsWrapper, !!on);\n\n        var ids = [\"power2\", \"length2\", \"maxDrop2\", \"ambientTemp2\", \"conductorConfigB\"];\n        for (var i = 0; i < ids.length; i++) setFieldVisibleById(ids[i], !!on);\n\nvar dropA = inRoot(\"maxDrop\");\nvar dropB = inRoot(\"maxDrop2\");\n\n\/\/ Adjust max voltage drop only when Cable B is activated\n\/\/ Rule:\n\/\/ - If the value is exactly 1 \u2192 change to 0.5\n\/\/ - If another value (e.g. 0.3) \u2192 do not touch\nfunction isExactlyOne(raw) {\n  var s = String(raw == null ? \"\" : raw).trim();\n  if (!s) return false;\n\n  s = s.replace(\",\", \".\");\n  var n = parseFloat(s);\n\n  return isFinite(n) && Math.abs(n - 1) < 1e-9;\n}\n\nif (on) {\n  if (dropA && isExactlyOne(dropA.value)) dropA.value = \"0.5\";\n  if (dropB && isExactlyOne(dropB.value)) dropB.value = \"0.5\";\n}\n\n      } finally {\n        uiSyncing = false;\n      }\n    }\n\nmodule.syncSeriesUI = function syncSeriesUI() {\n  if (!root) root = getCableRootElement();\n  if (!root) return;\n\n  var st = inRoot(\"seriesToggle\");\n  var on = !!(st && st.checked);\n\n  forceSeriesInputsVisibility(on);\n  applySeriesState(on);\n};\n\n    function getCalcMode() {\n      var radios = root ? root.querySelectorAll('input[name=\"calc_mode\"]') : null;\n      if (!radios || !radios.length) return \"fromLoad\";\n      for (var i = 0; i < radios.length; i++) {\n        if (radios[i].checked) return radios[i].value;\n      }\n      return \"fromLoad\";\n    }\n\n    var SYSTEM_VOLTAGE = 760;\n\n    var copperSections   = [1.5, 2.5, 4, 6, 10, 16];\n    var aluminumSections = [16, 25, 35, 50, 70, 95, 120, 150, 185, 240];\n\n    var copperExistingSections   = [1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240];\n    var aluminumExistingSections = aluminumSections.slice();\n\n    var resistivity = { Copper: 0.0175, Aluminum: 0.0283 };\n\n    var installFactor = { A1:0.70, A2:0.80, B1:0.85, C:1.00, D1:0.90, D2:0.85, E:1.00 };\n    var insulationFactor = { PVC70:1.00, XLPE90:1.20 };\n    var baseCurrentDensity = { Copper:10, Aluminum:7 };\n\n    var conductorConfigs = {\n      \"3-wire\": { parallelPaths:false, currentCarrying:2, name:\"3 conductors\", description:\"L+, L-, PE\" },\n      \"4-wire\": { parallelPaths:false, currentCarrying:2, name:\"4 conductors\", description:\"L+, L-, X, PE\" },\n      \"4-wire-shielded\": { parallelPaths:true, currentCarrying:4, name:\"4 conductors with shield\", description:\"2xL+, 2xL- (PE = shield)\" },\n      \"5-wire\": { parallelPaths:true, currentCarrying:4, name:\"5 conductors\", description:\"2xL+, 2xL-, PE\" }\n    };\n    \n        function formatConductorLabel(conductorType) {\n      var cfg = conductorConfigs[conductorType] || conductorConfigs[\"3-wire\"];\n      if (!cfg) return \"\";\n      var name = String(cfg.name || \"\").trim();\n      var desc = String(cfg.description || \"\").trim();\n      if (name && desc) return name + \" (\" + desc + \")\";\n      return name || desc || \"\";\n    }\n\n    function computeCurrent(input) {\n      return input.power * 1000 \/ SYSTEM_VOLTAGE;\n    }\n\n    function mapConductor(value) {\n      var map = { \"3\":\"3-wire\", \"4\":\"4-wire\", \"4_shield\":\"4-wire-shielded\", \"5\":\"5-wire\" };\n      return map[value] || \"3-wire\";\n    }\n\n    function buildInputFromDom(prefix) {\n      var suffix = prefix || \"\";\n\n      var powerEl  = suffix ? inRoot(\"power\" + suffix) : inRoot(\"power\");\n      var lengthEl = suffix ? inRoot(\"length\" + suffix) : inRoot(\"length\");\n      var dropEl   = suffix ? inRoot(\"maxDrop\" + suffix) : inRoot(\"maxDrop\");\n      var tempEl   = suffix ? inRoot(\"ambientTemp\" + suffix) : inRoot(\"ambientTemp\");\n      var instEl   = suffix ? inRoot(\"installMethod\" + suffix) : inRoot(\"installMethod\");\n      var insuEl   = suffix ? inRoot(\"insulationType\" + suffix) : inRoot(\"insulationType\");\n      var condEl;\nif (!suffix) condEl = inRoot(\"conductorConfigA\");\nelse if (String(suffix) === \"2\") condEl = inRoot(\"conductorConfigB\");\nelse condEl = inRoot(\"conductorConfig\" + suffix); \n\n      return {\n        cableType: \"DC\",\n        voltage: SYSTEM_VOLTAGE,\n        power: powerEl ? (toNumber(powerEl.value) || 0) : 0,\n        length: lengthEl ? (toNumber(lengthEl.value) || 0) : 0,\n        maxVoltageDrop: dropEl ? (toNumber(dropEl.value) || 0) : 0,\n        temperature: tempEl ? (toNumber(tempEl.value) || 20) : 20,\n        installMethod: instEl ? (instEl.value || \"C\") : \"C\",\n        insulationType: insuEl ? (insuEl.value || \"PVC70\") : \"PVC70\",\n        conductorType: mapConductor(condEl ? condEl.value : \"3\")\n      };\n    }\n\n    function buildKnownCableInputFromDom() {\n      var lengthEl = inRoot(\"length\");\n      var dropEl   = inRoot(\"maxDrop\");\n      var tempEl   = inRoot(\"ambientTemp\");\n      var instEl   = inRoot(\"installMethod\");\n      var insuEl   = inRoot(\"insulationType\");\n      var condEl   = inRoot(\"conductorConfigA\");\n      var cableSel = inRoot(\"knownCableTypeA\");\n\n      var material = \"Copper\";\n      var crossSection = 0;\n\n      if (cableSel && cableSel.value) {\n        var parts = cableSel.value.split(\"_\");\n        if (parts.length === 2) {\n          material = (parts[0] === \"ALU\") ? \"Aluminum\" : \"Copper\";\n          crossSection = toNumber(parts[1]) || 0;\n        }\n      }\n\n      return {\n        cableType: \"DC\",\n        voltage: SYSTEM_VOLTAGE,\n        length: lengthEl ? (toNumber(lengthEl.value) || 0) : 0,\n        maxVoltageDrop: dropEl ? (toNumber(dropEl.value) || 0) : 0,\n        temperature: tempEl ? (toNumber(tempEl.value) || 20) : 20,\n        installMethod: instEl ? (instEl.value || \"C\") : \"C\",\n        insulationType: insuEl ? (insuEl.value || \"PVC70\") : \"PVC70\",\n        conductorType: mapConductor(condEl ? condEl.value : \"3\"),\n        crossSection: crossSection,\n        material: material\n      };\n    }\n\n    function runSelection(input) {\n      if (!(input.power > 0 && input.length > 0)) return null;\n\n      var current = computeCurrent(input);\n      var tempCoeff = 0.004;\n      var config = conductorConfigs[input.conductorType] || conductorConfigs[\"3-wire\"];\n\n      var kInstall    = installFactor[input.installMethod] || 1.0;\n      var kInsulation = insulationFactor[input.insulationType] || 1.0;\n\n      var allSolutions = [];\n\n      function testConfiguration(material, crossSection) {\n        var numberOfCables = 1;\n        var rhoBase = resistivity[material];\n\n        var baseDensity = baseCurrentDensity[material] || 8;\n        var allowablePerCableBase = baseDensity * crossSection;\n        var allowablePerCable = allowablePerCableBase * kInsulation * kInstall;\n        var allowableTotal = allowablePerCable * numberOfCables;\n\n        var tempCorrection = 1 + tempCoeff * (input.temperature - 20);\n        var resistancePerConductor = (rhoBase * input.length \/ crossSection) * tempCorrection;\n\n        var effectiveResistance;\n        if (config.parallelPaths) effectiveResistance = resistancePerConductor \/ (2 * numberOfCables);\n        else effectiveResistance = resistancePerConductor \/ numberOfCables;\n\n        var voltageDrop = 2 * current * effectiveResistance;\n        var voltageDropPercent = voltageDrop \/ SYSTEM_VOLTAGE * 100;\n\n        var voltageDropOK = voltageDropPercent <= input.maxVoltageDrop;\n        var currentOK = current <= allowableTotal;\n\n        allSolutions.push({\n          crossSection: crossSection,\n          material: material,\n          numberOfCables: numberOfCables,\n          conductorType: input.conductorType,\n          current: current,\n          voltageDropPercent: voltageDropPercent,\n          allowableTotal: allowableTotal,\n          currentOK: currentOK,\n          isValid: voltageDropOK && currentOK\n        });\n      }\n\n      copperSections.forEach(function(cs) { testConfiguration(\"Copper\", cs); });\n      aluminumSections.forEach(function(cs) { testConfiguration(\"Aluminum\", cs); });\n\n      var validSolutions = allSolutions.filter(function(s) { return s.isValid; });\n      if (!validSolutions.length) return null;\n\n      validSolutions.sort(function(a, b) {\n        if (a.crossSection !== b.crossSection) return a.crossSection - b.crossSection;\n        if (a.material !== b.material) return a.material === \"Copper\" ? -1 : 1;\n        return 0;\n      });\n\n      return validSolutions[0];\n    }\n\n    function runInverseCalculation(input) {\n      if (!(input.crossSection > 0 && input.length > 0 && input.maxVoltageDrop > 0)) return null;\n\n      var tempCoeff = 0.004;\n      var config = conductorConfigs[input.conductorType] || conductorConfigs[\"3-wire\"];\n      \n      \n\n      var kInstall    = installFactor[input.installMethod] || 1.0;\n      var kInsulation = insulationFactor[input.insulationType] || 1.0;\n\n      var numberOfCables = 1;\n      var rhoBase = resistivity[input.material];\n      if (!rhoBase) return null;\n\n      var baseDensity = baseCurrentDensity[input.material] || 8;\n      var allowablePerCableBase = baseDensity * input.crossSection;\n      var allowablePerCable = allowablePerCableBase * kInsulation * kInstall;\n      var allowableTotal = allowablePerCable * numberOfCables;\n\n      var tempCorrection = 1 + tempCoeff * (input.temperature - 20);\n      var resistancePerConductor = (rhoBase * input.length \/ input.crossSection) * tempCorrection;\n\n      var effectiveResistance;\n      if (config.parallelPaths) effectiveResistance = resistancePerConductor \/ (2 * numberOfCables);\n      else effectiveResistance = resistancePerConductor \/ numberOfCables;\n\n      if (!(effectiveResistance > 0)) return null;\n\n      var maxVoltageDropAbsolute = input.maxVoltageDrop * input.voltage \/ 100;\n      var limitCurrentDrop = maxVoltageDropAbsolute \/ (2 * effectiveResistance);\n\n      var current = Math.min(allowableTotal, limitCurrentDrop);\n      if (!(current > 0)) return null;\n\n      var voltageDrop = 2 * current * effectiveResistance;\n      var voltageDropPercent = voltageDrop \/ input.voltage * 100;\n      var powerKW = current * input.voltage \/ 1000;\n\n      return {\n        crossSection: input.crossSection,\n        material: input.material,\n        conductorType: input.conductorType,\n        current: current,\n        voltageDropPercent: voltageDropPercent,\n        allowableTotal: allowableTotal,\n        powerKW: powerKW,\n        limitBy: (current === allowableTotal) ? \"ampacity\" : \"voltageDrop\"\n      };\n    }\n\n    function clearResults() {\n      setText(\"resultArea\", \"-\");\n      setText(\"resultMaterial\", \"-\");\n      setText(\"resultCurrent\", \"-\");\n      setText(\"resultNote\", \"-\");\n\n      setText(\"resultArea2\", \"-\");\n      setText(\"resultMaterial2\", \"-\");\n      setText(\"resultCurrent2\", \"-\");\n      setText(\"resultNote2\", \"\");\n\n      var seriesBox = inRoot(\"seriesResult\");\n      var seriesTotal = inRoot(\"resultSeriesTotal\");\n      if (seriesBox) seriesBox.style.display = \"none\";\n      if (seriesTotal) seriesTotal.textContent = \"\";\n    }\n\n    function setResultVisible(visible) {\n      var block = inRoot(\"ccResultAndDoc\");\n      if (!block) return;\n      block.classList.toggle(\"cc-hidden\", !visible);\n    }\n\n    function renderNoResult(message) {\n      clearResults();\n      setText(\"resultNote\", message || \"-\");\n    }\n\n    function renderSegmentResult(res, suffix) {\n      var suf = suffix || \"\";\n      var areaId = suf ? \"resultArea2\" : \"resultArea\";\n      var materialId = suf ? \"resultMaterial2\" : \"resultMaterial\";\n      var currentId = suf ? \"resultCurrent2\" : \"resultCurrent\";\n      var noteId = suf ? \"resultNote2\" : \"resultNote\";\n\n      setText(areaId, String(res.crossSection).replace(\".\", \",\") + \" mm\u00b2\");\n      setText(materialId, (res.material === \"Copper\" ? \"Copper\" : \"Aluminum\"));\n      setText(currentId, formatNumber(res.current, 1) + \" A\");\n      setText(noteId, res.voltageDropPercent.toFixed(2).replace(\".\", \",\") + \" %\");\n    }\n\n    function renderInverseResult(inv) {\n      setText(\"resultArea\", String(inv.crossSection).replace(\".\", \",\") + \" mm\u00b2\");\n      setText(\"resultMaterial\", (inv.material === \"Copper\" ? \"Copper\" : \"Aluminum\"));\n      setText(\"resultCurrent\", formatNumber(inv.current, 1) + \" A\");\n\n      var limitText = inv.limitBy === \"ampacity\"\n        ? \"Limiting factor: current-carrying capacity.\"\n        : \"Limiting factor: voltage drop.\";\n\n      setText(\n        \"resultNote\",\n        \"Max power \" + formatNumber(inv.powerKW, 1) + \" kW. Voltage drop \" + inv.voltageDropPercent.toFixed(2).replace(\".\", \",\") + \" %. \" + limitText\n      );\n    }\n\n    function validateInputsDetailed(mode) {\n      function hasValue(el) { return !!(el && String(el.value || \"\").trim()); }\n\n      var lenEl   = inRoot(\"length\");\n      var dropEl  = inRoot(\"maxDrop\");\n      var tempEl  = inRoot(\"ambientTemp\");\n      var powerEl = inRoot(\"power\");\n\n      if (mode === \"fromCable\") {\n        var cableSel = inRoot(\"knownCableTypeA\");\n        if (!cableSel || !cableSel.value) return { ok: false, message: \"Select an existing cable in the list.\" };\n        if (!hasValue(lenEl) || !hasValue(dropEl) || !hasValue(tempEl)) return { ok: false, message: \"Enter length, max voltage drop and temperature.\" };\n        return { ok: true, message: \"\" };\n      }\n\n      var seriesToggle = inRoot(\"seriesToggle\");\n      var seriesOn = !!(seriesToggle && seriesToggle.checked);\n\n      if (!hasValue(powerEl) || !hasValue(lenEl) || !hasValue(dropEl) || !hasValue(tempEl)) {\n        return { ok: false, message: \"Enter power, length, max voltage drop and temperature for cable A.\" };\n      }\n\n      if (seriesOn) {\n        var power2 = inRoot(\"power2\");\n        var len2   = inRoot(\"length2\");\n        var drop2  = inRoot(\"maxDrop2\");\n        var temp2  = inRoot(\"ambientTemp2\");\n\n        if (!hasValue(power2) || !hasValue(len2) || !hasValue(drop2) || !hasValue(temp2)) {\n          return { ok: false, message: \"Series calculation is enabled. Enter power, length, voltage drop and temperature for cable B.\" };\n        }\n      }\n\n      return { ok: true, message: \"\" };\n    }\n\n    function populateKnownCableOptions() {\n      var sel = inRoot(\"knownCableTypeA\");\n      if (!sel) return;\n\n      var currentValue = String(sel.value || \"\");\n      sel.innerHTML = \"\";\n\n      var placeholder = document.createElement(\"option\");\n      placeholder.value = \"\";\n      placeholder.textContent = \"Select cable type\";\n      placeholder.disabled = true;\n      sel.appendChild(placeholder);\n\n      copperExistingSections.forEach(function (cs) {\n        var opt = document.createElement(\"option\");\n        opt.value = \"CU_\" + cs;\n        opt.textContent = \"CU \" + cs + \" mm\u00b2\";\n        sel.appendChild(opt);\n      });\n\n      aluminumExistingSections.forEach(function (cs) {\n        var opt2 = document.createElement(\"option\");\n        opt2.value = \"ALU_\" + cs;\n        opt2.textContent = \"ALU \" + cs + \" mm\u00b2\";\n        sel.appendChild(opt2);\n      });\n\n      if (currentValue) {\n        var hasOption = false;\n        for (var i = 0; i < sel.options.length; i++) {\n          if (sel.options[i].value === currentValue) { hasOption = true; break; }\n        }\n        sel.value = hasOption ? currentValue : \"\";\n      } else {\n        sel.value = \"\";\n      }\n\n      placeholder.selected = (sel.value === \"\");\n    }\n\n    function setModeUI() {\n      if (!root) return;\n\n      var mode = getCalcMode();\n      var fromLoad = (mode === \"fromLoad\");\n\n      var powerFieldA = inRoot(\"powerFieldA\");\n      var knownCableFieldsA = inRoot(\"knownCableFieldsA\");\n\n      var seriesToggle = inRoot(\"seriesToggle\");\n      var seriesInputsWrapper = getSeriesInputsEl();\n      var seriesInputsExact = inRoot(\"seriesInputs\");\n      var seriesResult = getSeriesResultEl();\n      var seriesWrap = root ? root.querySelector(\".cc-series-wrap\") : null;\n\n      if (powerFieldA) setBlockVisible(powerFieldA, fromLoad);\n      else setBlockVisible(findBlockForInput(inRoot(\"power\")), fromLoad);\n\n      if (knownCableFieldsA) setBlockVisible(knownCableFieldsA, !fromLoad);\n      else setBlockVisible(findBlockForInput(inRoot(\"knownCableTypeA\")), !fromLoad);\n\n      if (!fromLoad) {\n        if (seriesToggle) seriesToggle.checked = false;\n\n        applySeriesState(false);\n\n        if (seriesInputsWrapper) setBlockVisible(seriesInputsWrapper, false);\n        if (seriesInputsExact) setBlockVisible(seriesInputsExact, false);\n        if (seriesResult) seriesResult.style.display = \"none\";\n        if (seriesWrap) setBlockVisible(seriesWrap, false);\n      } else {\n        if (seriesWrap) setBlockVisible(seriesWrap, true);\n\n        var on = !!(seriesToggle && seriesToggle.checked);\n        applySeriesState(on);\n\n        if (seriesInputsWrapper) setBlockVisible(seriesInputsWrapper, on);\n        if (seriesInputsExact) setBlockVisible(seriesInputsExact, on);\n      }\n\n      styleToggleButton(inRoot(\"modeBtnFromLoad\"), fromLoad);\n      styleToggleButton(inRoot(\"modeBtnFromCable\"), !fromLoad);\n    }\n\n    function markDirty() {\n      clearResults();\n      setResultVisible(false);\n\n      if (typeof module.onDirty === \"function\") {\n        try { module.onDirty(); } catch (e) {}\n      }\n    }\n\n    function calculate() {\n      if (!root) return false;\n      setCableError(\"\", \"\");\n      \n      window.__cableLastResult = { ok: false };\n\n      var mode = getCalcMode();\n      var v = validateInputsDetailed(mode);\n\n      \nif (!v.ok) {\n  setCableError(\"validation\", v.message || \"Please fill in all required fields.\");\n  renderNoResult(v.message);\n  setResultVisible(true);\n  window.__cableLastResult = { ok: false };\n  return false;\n}\n\n      if (mode === \"fromCable\") {\n        var invInput = buildKnownCableInputFromDom();\n        var invResult = runInverseCalculation(invInput);\n\n        if (!invResult) {\n          renderNoResult(\"With the given conditions no allowed load can be calculated. Adjust cable data or max voltage drop.\");\n          setResultVisible(true);\n          window.__cableLastResult = { ok: false };\n          return false;\n        }\n\n        clearResults();\n        renderInverseResult(invResult);\n        setResultVisible(true);\n        \n        window.__cableSystemVoltageText = \"DC \" + SYSTEM_VOLTAGE + \" V\";\n\n        window.__cableLastResult = {\n          ok: true,\n          summary: \"Cable sizing completed\",\n          aText:\n  \"Selected cable: \" +\n  invResult.crossSection + \" mm\u00b2 \" +\n  (invResult.material === \"Copper\" ? \"copper\" : \"aluminum\") +\n  \", \" + formatConductorLabel(invResult.conductorType),\n          bText: \"\",\n          totalText: \"Voltage drop: \" + invResult.voltageDropPercent.toFixed(2).replace(\".\", \",\") + \" %.\"\n        };\n\n        return true;\n      }\n\n      var seriesToggle = inRoot(\"seriesToggle\");\n      var seriesOn = !!(seriesToggle && seriesToggle.checked);\n\n      var inputA = buildInputFromDom(\"\");\n      var resultA = runSelection(inputA);\n\nif (!resultA) {\n  var msg = \"The calculator supports aluminum cables up to 240 mm\u00b2. For projects requiring larger cable sizes we recommend sizing via dedicated design work.\";\n  setCableError(\"oversize\", msg);\n  renderNoResult(msg);\n  setResultVisible(true);\n  window.__cableLastResult = { ok: false };\n  return false;\n}\n\n      if (!seriesOn) {\n        clearResults();\n        renderSegmentResult(resultA, \"\");\n        setResultVisible(true);\n        window.__cableSystemVoltageText = \"DC \" + SYSTEM_VOLTAGE + \" V\";\n\n        window.__cableLastResult = {\n          ok: true,\n          summary: \"Cable sizing completed\",\n          aText:\n  resultA.crossSection + \" mm\u00b2 \" +\n  (resultA.material === \"Copper\" ? \"copper\" : \"aluminum\") +\n  \", \" + formatConductorLabel(resultA.conductorType),\n          bText: \"\",\n          totalText: \"Voltage drop: \" + resultA.voltageDropPercent.toFixed(2).replace(\".\", \",\") + \" %.\"\n\n        };\n\n        return true;\n      }\n\n      var inputB = buildInputFromDom(\"2\");\n      var resultB = runSelection(inputB);\n\nif (!resultB) {\n  var msgB = \"The calculator supports aluminum cables up to 240 mm\u00b2. For projects requiring larger cable sizes we recommend sizing via dedicated design work.\";\n  setCableError(\"oversize\", msgB);\n  renderNoResult(msgB);\n  setResultVisible(true);\n  window.__cableLastResult = { ok: false };\n  return false;\n}\n\n      clearResults();\n      renderSegmentResult(resultA, \"\");\n      renderSegmentResult(resultB, \"2\");\n\n      var totalDropPercent = resultA.voltageDropPercent + resultB.voltageDropPercent;\n      var seriesBox = inRoot(\"seriesResult\");\n      var seriesTotal = inRoot(\"resultSeriesTotal\");\n      if (seriesBox) seriesBox.style.display = \"block\";\n      if (seriesTotal) seriesTotal.textContent = \"Series: \" + totalDropPercent.toFixed(2).replace(\".\", \",\") + \" %.\";\n\n      setResultVisible(true);\n      window.__cableSystemVoltageText = \"DC \" + SYSTEM_VOLTAGE + \" V\";\n\n      window.__cableLastResult = {\n        ok: true,\n        summary: \"Cable sizing completed\",\n        aText:\n  resultA.crossSection + \" mm\u00b2 \" +\n  (resultA.material === \"Copper\" ? \"copper\" : \"aluminum\") +\n  \", \" + formatConductorLabel(resultA.conductorType),\n        bText:\n  resultB.crossSection + \" mm\u00b2 \" +\n  (resultB.material === \"Copper\" ? \"copper\" : \"aluminum\") +\n  \", \" + formatConductorLabel(resultB.conductorType),\n        totalText: \"Series: \" + totalDropPercent.toFixed(2).replace(\".\", \",\") + \" %.\"\n      };\n\n      return true;\n    }\n\n    module.init = function init() {\n      root = getCableRootElement();\n      if (!root) return false;\n\n      if (root.getAttribute(\"data-cc-initialized\") === \"1\") return true;\n      root.setAttribute(\"data-cc-initialized\", \"1\");\n\n      populateKnownCableOptions();\n      setModeUI();\n\n      module.syncSeriesUI();\n      \n      \n      \/\/ Default max voltage drop on first load (if empty)\n(function applyDropDefaultsOnInit() {\n  if (defaultsApplied) return;\n\n  var dropA = inRoot(\"maxDrop\");\n  var dropB = inRoot(\"maxDrop2\");\n\n  if (dropA && !String(dropA.value || \"\").trim()) dropA.value = \"0.5\";\n  if (dropB && !String(dropB.value || \"\").trim()) dropB.value = \"0.5\";\n\n  defaultsApplied = true;\n})();\n      \n      \n      \n\n      clearResults();\n      setResultVisible(false);\n\n      var btnLoad = inRoot(\"modeBtnFromLoad\");\n      var btnCable = inRoot(\"modeBtnFromCable\");\n      var radioLoad = inRoot(\"modeFromLoad\");\n      var radioCable = inRoot(\"modeFromCable\");\n\n      function setMode(mode) {\n        if (radioLoad) radioLoad.checked = (mode === \"fromLoad\");\n        if (radioCable) radioCable.checked = (mode === \"fromCable\");\n        if (mode === \"fromCable\") populateKnownCableOptions();\n        setModeUI();\n        markDirty();\n      }\n\n      if (btnLoad) btnLoad.addEventListener(\"click\", function (e) { e.preventDefault(); setMode(\"fromLoad\"); });\n      if (btnCable) btnCable.addEventListener(\"click\", function (e) { e.preventDefault(); setMode(\"fromCable\"); });\n      if (radioLoad) radioLoad.addEventListener(\"change\", function () { setModeUI(); markDirty(); });\n      if (radioCable) radioCable.addEventListener(\"change\", function () { setModeUI(); markDirty(); });\n\n      var seriesToggle = inRoot(\"seriesToggle\");\n      if (seriesToggle) {\n        forceSeriesInputsVisibility(!!seriesToggle.checked);\n        applySeriesState(!!seriesToggle.checked);\n\n        seriesToggle.addEventListener(\"change\", function () {\n          if (uiSyncing) return;\n\n          var on = !!seriesToggle.checked;\n\n          forceSeriesInputsVisibility(on);\n          applySeriesState(on);\n\n          markDirty();\n        });\n      }\n\n      var inputs = root.querySelectorAll(\"input, select, textarea\");\n      for (var i = 0; i < inputs.length; i++) {\n        (function (el) {\n          var ev = (el.tagName === \"SELECT\") ? \"change\" : \"input\";\n          el.addEventListener(ev, function () { markDirty(); }, true);\n          if (ev !== \"change\") el.addEventListener(\"change\", function () { markDirty(); }, true);\n        })(inputs[i]);\n      }\n\n      return true;\n    };\n\n    module.calculate = function () { return calculate(); };\n    module.reset = function () { markDirty(); };\n\n    module.validateForSystem = function () {\n      if (!root) root = getCableRootElement();\n      if (!root) return { ok: false, message: \"The cable calculator could not be initialized.\" };\n      var mode = getCalcMode();\n      return validateInputsDetailed(mode);\n    };\n\n    module.prefillPowerKw = function (kw) {\n      if (!root) root = getCableRootElement();\n      if (!root) return;\n      var powerEl = inRoot(\"power\");\n      if (!powerEl) return;\n      var n = toNumber(kw);\n      if (!isFinite(n) || n <= 0) return;\n      powerEl.value = String(Math.round(n)).replace(\".\", \",\");\n      markDirty();\n    };\n\n    module._getRoot = function () { return root; };\n\n    return module;\n  })();\n\n \/* =========================================================\n   Cable toggle expand\n========================================================= *\/\n\nvar elCableToggle = null;\n\n\n\n\n  function hideAllResults() {\n    if (elAfterCalc) elAfterCalc.style.display = \"none\";\n    if (elResultBox) elResultBox.style.display = \"none\";\n\n    if (elResEnergyHubModel) elResEnergyHubModel.textContent = \"\";\n    if (elResBatterySummary) elResBatterySummary.textContent = \"\";\n    if (elResInstalled) elResInstalled.textContent = \"\";\n    if (elResNumSso) elResNumSso.textContent = \"\";\n    if (elResMinPanels) elResMinPanels.textContent = \"\";\n    if (elResMaxPanels) elResMaxPanels.textContent = \"\";\n    if (elResMinMaxPanels) elResMinMaxPanels.textContent = \"\";\n\n    setSolarResultVisible(false);\n\n    setBatteryResultVisible(false);\n\n    setSolarTechToggleRowVisible(false);\n    setSolarTechVisible(false);\n\n    var dist = byId(\"sysconfDistributionLines\");\n    if (dist) dist.innerHTML = \"\";\n\n    renderArticles([]);\n\n    clearCableInSystemResult();\n    \n    setDocumentationVisible(false);\n    \n    window.__cableLastResult = { ok: false };\nsyncDocumentationCableFields();\n\nupdateLastVisibleResultDivider();\n  }\n  \n  \n  \n  \n  function syncDocumentationCableFields() {\n  var res = window.__cableLastResult || {};\n  var hasA = !!(res && res.ok && String(res.aText || \"\").trim());\n  var hasB = !!(res && res.ok && String(res.bText || \"\").trim());\n\n  var rowA = byId(\"tsCableNameRowA\");\n  var rowB = byId(\"tsCableNameRowB\");\n\n  if (rowA) rowA.classList.toggle(\"ts-hidden\", !hasA);\n  if (rowB) rowB.classList.toggle(\"ts-hidden\", !hasB);\n}\n  \nfunction setDocumentationVisible(visible) {\n  var wrap = byId(\"tsDocSectionSystem\");\n  if (wrap) wrap.style.display = visible ? \"\" : \"none\";\n\n  var pdfBtn = byId(\"tsCreatePdfBtn\");\n  if (pdfBtn) {\n    pdfBtn.disabled = !visible;\n    pdfBtn.setAttribute(\"aria-disabled\", visible ? \"false\" : \"true\");\n    pdfBtn.style.pointerEvents = visible ? \"\" : \"none\";\n    pdfBtn.style.opacity = visible ? \"\" : \"0.5\";\n  }\n}\n\n\n\nfunction invalidateCalculation() {\n  hideCalcAlert();\n  if (!hasCalculated) return;\n  hasCalculated = false;\n  hideAllResults();\n  clearCableInSystemResult();\n  setSolarTechToggleRowVisible(false);\nsetSolarTechVisible(false);\nsetDocumentationVisible(false);\n}\n\nfunction setCableExpanded(state, opts) {\n  var on = state;\n\n  if (typeof on !== \"boolean\") {\n    opts = on;\n    on = !!(elCableToggle && elCableToggle.checked);\n  }\n\n  var doScroll = true;\n  if (typeof opts === \"boolean\") doScroll = opts;\n  else if (opts && typeof opts === \"object\" && Object.prototype.hasOwnProperty.call(opts, \"scroll\")) {\n    doScroll = (opts.scroll !== false);\n  }\n\n  var cableSection = byId(\"tsCableSectionSystem\");\n  if (!cableSection) return;\n\n  var cableExpand = cableSection.querySelector(\".ts-cable-expand\");\n  if (!cableExpand) return;\n\n  if (on) {\n    cableExpand.classList.remove(\"ts-hidden\");\n    cableExpand.setAttribute(\"aria-hidden\", \"false\");\n\n\nvar inited = cableModule.init();\nif (inited) {\n  cableModule.syncSeriesUI();\n}\n    \n    \n    \n    \n  } else {\n    cableExpand.classList.add(\"ts-hidden\");\n    cableExpand.setAttribute(\"aria-hidden\", \"true\");\n    cableModule.reset();\n  }\n}\n\n\n\nfunction ensureCableModuleInitialized() {\n  try {\n    cableModule.init();\n  } catch (e) {}\n}\n\nfunction bindCableToggleWhenReady() {\n  var t = document.getElementById(\"tsCableToggle\");\n  if (!t) return false;\n\n  if (elCableToggle && elCableToggle !== t) {\n    try {\n      elCableToggle.removeEventListener(\"change\", elCableToggle.__tsOnChange);\n      elCableToggle.removeEventListener(\"click\", elCableToggle.__tsOnClick);\n    } catch (e) {}\n  }\n\n  if (t.__tsBound === true) {\n    elCableToggle = t;\n    return true;\n  }\n\n  elCableToggle = t;\n  t.__tsBound = true;\n\nt.__tsOnChange = function () {\n  var on = !!t.checked;\n  setCableExpanded(on, { scroll: false });\n  invalidateCalculation();\n};\n\nt.__tsOnClick = function () {\n  setTimeout(function () {\n    var on = !!t.checked;\n    setCableExpanded(on, { scroll: false });\n    invalidateCalculation();\n  }, 0);\n};\n\n\n  t.addEventListener(\"change\", t.__tsOnChange);\n  t.addEventListener(\"click\", t.__tsOnClick);\n\n  setCableExpanded(!!t.checked, { scroll: false });\n\n  ensureCableModuleInitialized();\n\n  return true;\n}\n\nbindCableToggleWhenReady();\nensureCableModuleInitialized();\n\n(function keepCableBound() {\n  var timer = window.setInterval(function () {\n    var ok = bindCableToggleWhenReady();\n    ensureCableModuleInitialized();\n\n    if (elCableToggle && !elCableToggle.isConnected) {\n      elCableToggle = null;\n      return;\n    }\n\n    if (ok && elCableToggle && elCableToggle.isConnected) {\n      window.clearInterval(timer);\n    }\n  }, 250);\n})();\n\ncableModule.onDirty = function () { invalidateCalculation(); };\n\n\n\n\n\n\n\n  \/* =========================================================\n     System DOM\n  ========================================================= *\/\n  var elForm = byId(\"sysconfCalculatorForm\");\n\n  var elNumPanels   = byId(\"sysconfNumPanels\");\n  var elPanelSelect = byId(\"sysconfPanelSelect\");\n  var elMountType   = byId(\"sysconfMountType\");\n\n  var elManualGroup = byId(\"sysconfManualModelGroup\");\n  var elManualModel = byId(\"sysconfManualModel\");\n\n  var elPmax     = byId(\"sysconfPanelPmax\");\n  var elVmp      = byId(\"sysconfPanelVmp\");\n  var elVoc      = byId(\"sysconfPanelVoc\");\n  var elImp      = byId(\"sysconfPanelImp\");\n  var elIsc      = byId(\"sysconfPanelIsc\");\n  var elVocCoeff = byId(\"sysconfPanelVocCoeff\");\n\n  var elBatterySelect = byId(\"sysconfBatterySelect\");\n  var elNumEso        = byId(\"sysconfNumEso\");\n\n  var elCalcBtn = byId(\"sysconfCalcBtn\");\n\n  var elAfterCalc     = byId(\"sysconfAfterCalc\");\n  var elResultBox     = byId(\"sysconfResultLinesBox\");\n  var elArticlesLines = byId(\"sysconfArticlesLines\");\n  \nvar elSolarTechWrap = byId(\"sysconfSolarTechToggleRow\");\nvar elSolarTechToggleBtn = byId(\"sysconfSolarTechToggleBtn\");\nvar elSolarTechCard = byId(\"sysconfSolarTechCard\");\nvar elSolarTechToggleText = byId(\"sysconfSolarTechToggleText\");\n\nvar elResInstalled      = byId(\"sysconfResInstalledPower\");\nvar elResNumSso         = byId(\"sysconfResNumSso\");\nvar elResMinMaxPanels   = byId(\"sysconfResMinMaxPanelsPerSso\");\nvar elResMinPanels      = byId(\"sysconfResMinPanelsPerSso\");\nvar elResMaxPanels      = byId(\"sysconfResMaxPanelsPerSso\");\n\n  var elResEnergyHubModel = byId(\"sysconfResEnergyHubModel\");\n  var elResBatterySummary = byId(\"sysconfResBatterySummary\");\n\n  var elSolarBlock     = byId(\"sysconfSolarBlock\");\n  var elSolarSeparator = byId(\"sysconfSolarSeparator\");\n\n  var elResVmpNominal = byId(\"sysconfResVmpNominal\");\n  var elResVmpMin     = byId(\"sysconfResVmpMin\");\n  var elResVmpMax     = byId(\"sysconfResVmpMax\");\n  var elResVocMax     = byId(\"sysconfResVocMax\");\n  var elResImp        = byId(\"sysconfResImp\");\n  var elResIsc        = byId(\"sysconfResIsc\");\n\n  var elMinTemp = byId(\"sysconfMinTemperature\");\n  var elMaxTemp = byId(\"sysconfMaxTemperature\");\n\n  var elCalcAlert = byId(\"sysconfCalcAlert\");\n  \n  function setPanelInputsReadOnly(flag) {\n  [elPmax, elVmp, elVoc, elImp, elIsc, elVocCoeff].forEach(function (el) {\n    if (!el) return;\n    el.readOnly = flag;\n  });\n}\n\n  function hideCalcAlert() {\n    if (!elCalcAlert) return;\n    elCalcAlert.style.display = \"none\";\n    elCalcAlert.textContent = \"\";\n  }\n\n  function showCalcAlert(msg) {\n    if (!elCalcAlert) return;\n    elCalcAlert.textContent = msg || \"\";\n    elCalcAlert.style.display = msg ? \"\" : \"none\";\n  }\n\n  function renderArticles(rows) {\n    if (!elArticlesLines) return;\n    while (elArticlesLines.firstChild) elArticlesLines.removeChild(elArticlesLines.firstChild);\n\n    (rows || []).forEach(function (r) {\n      var rowEl = document.createElement(\"div\");\n      rowEl.classList.add(\"sso-result-line\", \"sysconf-articles-row\");\n\n      var qtyEl = document.createElement(\"div\");\n      qtyEl.className = \"sysconf-col-qty\";\n      qtyEl.textContent = (r && r.qty != null) ? (r.qty + \" pcs\") : \"\";\n\n      var enrEl = document.createElement(\"div\");\n      enrEl.className = \"sysconf-col-enr\";\n      enrEl.textContent = (r && r.enr) ? String(r.enr) : \"\";\n\n      var nameEl = document.createElement(\"div\");\n      nameEl.className = \"sysconf-col-name\";\n      nameEl.textContent = (r && r.name) ? String(r.name) : \"\";\n\n      rowEl.appendChild(qtyEl);\n      rowEl.appendChild(enrEl);\n      rowEl.appendChild(nameEl);\n\n      elArticlesLines.appendChild(rowEl);\n    });\n  }\n\n  function setBatteryResultVisible(visible) {\n    var row = document.querySelector(\".sysconf-row-battery\");\n    if (!row) return;\n    row.style.display = visible ? \"\" : \"none\";\n  }\n\n  function setSolarResultVisible(visible) {\n    var show = !!visible;\n    if (elSolarBlock) elSolarBlock.style.display = show ? \"\" : \"none\";\n    if (elSolarSeparator) elSolarSeparator.style.display = show ? \"\" : \"none\";\n  }\n  \nfunction setSolarTechToggleRowVisible(visible) {\n  var row = document.getElementById(\"sysconfSolarTechToggleRow\");\n  if (!row) return;\n\n  row.style.display = visible ? \"\" : \"none\";\n  row.setAttribute(\"aria-hidden\", visible ? \"false\" : \"true\");\n\n  var wrap = document.getElementById(\"sysconfSolarTechWrap\");\n  if (wrap) {\n    wrap.classList.toggle(\"ts-hidden\", !visible);\n    wrap.setAttribute(\"aria-hidden\", visible ? \"false\" : \"true\");\n  }\n}\n\n\n\nfunction hideCableSummaryRowAlways() {\n  var summaryEl = byId(\"sysconfResCableSummary\");\n  if (!summaryEl) return;\n\n  var row =\n    summaryEl.closest(\".sso-result-line\") ||\n    summaryEl.closest(\".sysconf-result-line\") ||\n    summaryEl.closest(\"tr\") ||\n    summaryEl.parentElement;\n\n  if (row) row.style.display = \"none\";\n}\nfunction showCableInSystemResult(payload) {\n  hideCableSummaryRowAlways();\n\n  var wrap = byId(\"sysconfCableCardWrap\");\n  var lineA = byId(\"sysconfCableLineA\");\n  var lineB = byId(\"sysconfCableLineB\");\n  var lineT = byId(\"sysconfCableLineTotal\");\n\n  function setById(id, val) {\n    var el = byId(id);\n    if (!el) return;\n    el.textContent = (val == null || val === \"\") ? \"-\" : String(val);\n  }\n\n  if (!wrap) return;\n\n  setElDisplay(lineA, false);\n  setElDisplay(lineB, false);\n  setElDisplay(lineT, false);\n  setElDisplay(wrap, false);\n\n  if (!payload || !payload.ok) return;\n\n  var any = false;\n\n  if (payload.aText) {\n    any = true;\n    setElDisplay(lineA, true);\n    setById(\"sysconfResCableA\", payload.aText);\n  }\n\n  if (payload.bText) {\n    any = true;\n    setElDisplay(lineB, true);\n    setById(\"sysconfResCableB\", payload.bText);\n  }\n\n  if (payload.totalText) {\n    any = true;\n    setElDisplay(lineT, true);\n    setById(\"sysconfResCableTotal\", payload.totalText);\n  }\n\n  setElDisplay(wrap, any);\n}\n\n\n  function clearCableInSystemResult() {\n    var wrap = byId(\"sysconfCableCardWrap\");\n    if (wrap) setElDisplay(wrap, false);\n\n    var a = byId(\"sysconfCableLineA\");\n    var b = byId(\"sysconfCableLineB\");\n    var t = byId(\"sysconfCableLineTotal\");\n    if (a) a.style.display = \"none\";\n    if (b) b.style.display = \"none\";\n    if (t) t.style.display = \"none\";\n  }\n\n  \/* =========================================================\n     Data maps\n  ========================================================= *\/\n  var panelMap = {};\n  panelsList.forEach(function (p, i) {\n    if (!p) return;\n    var key = (p.id != null) ? String(p.id) : String(i);\n    panelMap[key] = p;\n  });\n\n  var batteryMap = {};\n  batteries.forEach(function (b, i) {\n    if (!b) return;\n    var key = (b.id != null) ? String(b.id) : String(i);\n    batteryMap[key] = b;\n  });\n\nfunction initPanelSelect() {\n  if (!elPanelSelect) return;\n\n  \/\/ Rensa\n  elPanelSelect.innerHTML = \"\";\n\n  \/\/ 1) Placeholder \u00f6verst\n  var placeholder = document.createElement(\"option\");\n  placeholder.value = \"\";\n  placeholder.textContent = \"Select model\";\n  elPanelSelect.appendChild(placeholder);\n\n  \/\/ 2) MANUELLT VAL \u2013 direkt under placeholder\n  var manualOpt = document.createElement(\"option\");\n  manualOpt.value = \"manual\";\n  manualOpt.textContent = \"Other panel, enter values manually\";\n  elPanelSelect.appendChild(manualOpt);\n\n  \/\/ 3) \u00d6vriga panelmodeller\n  panelsList.forEach(function (p, i) {\n    if (!p || !p.modell) return;\n    var opt = document.createElement(\"option\");\n    opt.value = (p.id != null) ? String(p.id) : String(i);\n    opt.textContent = p.modell;\n    elPanelSelect.appendChild(opt);\n  });\n\n  \/\/ Init logik runt paneldata-togglen\n  initPanelDataToggle();\n  setTimeout(function () {\n    handlePanelSelectionChange();\n    updatePanelDataToggleVisibility();\n  }, 0);\n\n  updatePanelDataToggleVisibility();\n}\n\n  function initBatterySelect() {\n    if (!elBatterySelect) return;\n    elBatterySelect.innerHTML = '<option value=\"\">Select battery type<\/option>';\n    batteries.forEach(function (b, i) {\n      if (!b || !b.name) return;\n      var opt = document.createElement(\"option\");\n      opt.value = (b.id != null) ? String(b.id) : String(i);\n      var e = toNumber(b.energy_kwh);\n      opt.textContent = isFinite(e) ? (b.name + \" \" + formatNumber(e, 1) + \" kWh\") : b.name;\n      elBatterySelect.appendChild(opt);\n    });\n  }\n\n  function getPanelField(panelObj, keys) {\n    if (!panelObj) return NaN;\n    for (var i = 0; i < keys.length; i++) {\n      var k = keys[i];\n      if (panelObj[k] !== undefined && panelObj[k] !== null && String(panelObj[k]).trim() !== \"\") {\n        var n = toNumber(panelObj[k]);\n        if (isFinite(n)) return n;\n      }\n    }\n    return NaN;\n  }\n\n  function buildPanelForCalculation() {\n    var panelId = String((elPanelSelect && elPanelSelect.value) || \"\");\n    if (!panelId) return null;\n\n    if (panelId === \"manual\") {\n      var pmax = toNumber(elPmax && elPmax.value);\n      var vmp = toNumber(elVmp && elVmp.value);\n      var voc = toNumber(elVoc && elVoc.value);\n      var imp = toNumber(elImp && elImp.value);\n      var isc = toNumber(elIsc && elIsc.value);\n      var coeff = toNumber(elVocCoeff && elVocCoeff.value);\n\n      return {\n        modell: String((elManualModel && elManualModel.value) || \"Manual panel\"),\n        pmax: isFinite(pmax) ? pmax : NaN,\n        vmp: isFinite(vmp) ? vmp : NaN,\n        voc: isFinite(voc) ? voc : NaN,\n        imp: isFinite(imp) ? imp : NaN,\n        isc: isFinite(isc) ? isc : NaN,\n        voc_temp_coeff: isFinite(coeff) ? coeff : NaN\n      };\n    }\n\n    var p = panelMap[panelId] || null;\n    if (!p) return null;\n\n    return {\n      modell: String(p.modell || p.model || p.name || \"\"),\n      pmax: getPanelField(p, [\"pmax\", \"Pmax\", \"panel_pmax\", \"sysconf_pmax\", \"sysconf_Pmax\"]),\n      vmp: getPanelField(p, [\"vmp\", \"Vmp\", \"vmpp\", \"Vmpp\", \"panel_vmp\", \"sysconf_vmp\", \"sysconf_Vmp\"]),\n      voc: getPanelField(p, [\"voc\", \"Voc\", \"panel_voc\", \"sysconf_voc\", \"sysconf_Voc\"]),\n      imp: getPanelField(p, [\"imp\", \"Imp\", \"impp\", \"Impp\", \"panel_imp\", \"sysconf_imp\", \"sysconf_Imp\"]),\n      isc: getPanelField(p, [\"isc\", \"Isc\", \"panel_isc\", \"sysconf_isc\", \"sysconf_Isc\"]),\n      voc_temp_coeff: getPanelField(p, [\"voc_temp_coeff\", \"vocCoeff\", \"voc_tempcoefficient\", \"temp_coeff_voc\", \"sysconf_voc_temp_coeff\"])\n    };\n  }\n  \n  \n  function setInputValue(el, value) {\n  if (!el) return;\n  if (value == null || !isFinite(value)) { el.value = \"\"; return; }\n  el.value = String(value).replace(\".\", \",\");\n}\n\nfunction updatePanelDataFieldsFromSelection() {\n  if (!elPanelSelect) return;\n\n  var panelId = String(elPanelSelect.value || \"\");\n  var isManual = (panelId === \"manual\");\n\n  if (isManual) return;\n\n  if (!panelId) {\n    setInputValue(elPmax, NaN);\n    setInputValue(elVmp, NaN);\n    setInputValue(elVoc, NaN);\n    setInputValue(elImp, NaN);\n    setInputValue(elIsc, NaN);\n    setInputValue(elVocCoeff, NaN);\n    return;\n  }\n\n  var p = panelMap[panelId] || null;\n  if (!p) return;\n\n  var pmax = getPanelField(p, [\"pmax\", \"Pmax\", \"panel_pmax\", \"sysconf_pmax\", \"sysconf_Pmax\"]);\n  var vmp  = getPanelField(p, [\"vmp\", \"Vmp\", \"vmpp\", \"Vmpp\", \"panel_vmp\", \"sysconf_vmp\", \"sysconf_Vmp\"]);\n  var voc  = getPanelField(p, [\"voc\", \"Voc\", \"panel_voc\", \"sysconf_voc\", \"sysconf_Voc\"]);\n  var imp  = getPanelField(p, [\"imp\", \"Imp\", \"impp\", \"Impp\", \"panel_imp\", \"sysconf_imp\", \"sysconf_Imp\"]);\n  var isc  = getPanelField(p, [\"isc\", \"Isc\", \"panel_isc\", \"sysconf_isc\", \"sysconf_Isc\"]);\n  var coef = getPanelField(p, [\"voc_temp_coeff\", \"vocCoeff\", \"voc_tempcoefficient\", \"temp_coeff_voc\", \"sysconf_voc_temp_coeff\"]);\n\n  setInputValue(elPmax, pmax);\n  setInputValue(elVmp, vmp);\n  setInputValue(elVoc, voc);\n  setInputValue(elImp, imp);\n  setInputValue(elIsc, isc);\n  setInputValue(elVocCoeff, coef);\n}\n\nfunction handlePanelSelectionChange() {\n  if (!elPanelSelect) return;\n\n  var panelId = String(elPanelSelect.value || \"\");\n  var isManual = (panelId === \"manual\");\n\n  \/\/ Visa\/d\u00f6lj manual name-f\u00e4ltet\n  if (elManualGroup) elManualGroup.style.display = isManual ? \"\" : \"none\";\n\n  \/\/ G\u00f6r paneldata-f\u00e4lt redigerbara vid manual, annars l\u00e5sta\n  setPanelInputsReadOnly(!isManual);\n\n  \/\/ Fyll paneldata fr\u00e5n ACF f\u00f6r \u201cvanliga\u201d modeller\n  updatePanelDataFieldsFromSelection();\n\n  var toggleWrap = byId(\"sysconfPanelDataToggleWrap\");\n  var toggleRow  = byId(\"sysconfPanelDataToggleRow\");\n  var group      = byId(\"sysconfPanelDataGroup\");\n\n  \/\/ Ingen modell vald\n  if (!panelId) {\n    if (toggleWrap) {\n      toggleWrap.classList.add(\"ts-hidden\");\n      toggleWrap.setAttribute(\"aria-hidden\", \"true\");\n    }\n    if (toggleRow) toggleRow.setAttribute(\"aria-expanded\", \"false\");\n    if (group) {\n      group.classList.add(\"ts-hidden\");\n      group.setAttribute(\"aria-hidden\", \"true\");\n      group.style.display = \"none\";\n    }\n    return;\n  }\n\n  \/\/ MANUAL: g\u00f6m toggle, visa paneldata-gruppen direkt\n  if (isManual) {\n    if (toggleWrap) {\n      toggleWrap.classList.add(\"ts-hidden\");\n      toggleWrap.setAttribute(\"aria-hidden\", \"true\");\n    }\n    if (toggleRow) toggleRow.setAttribute(\"aria-expanded\", \"false\");\n    if (group) {\n      group.classList.remove(\"ts-hidden\");\n      group.setAttribute(\"aria-hidden\", \"false\");\n      group.style.display = \"\";\n    }\n    return;\n  }\n\n  \/\/ ACF\u2011panel: visa toggle-raden, h\u00e5ll gruppen st\u00e4ngd tills anv\u00e4ndaren klickar\n  if (toggleWrap) {\n    toggleWrap.classList.remove(\"ts-hidden\");\n    toggleWrap.setAttribute(\"aria-hidden\", \"false\");\n  }\n  if (toggleRow) toggleRow.setAttribute(\"aria-expanded\", \"false\");\n  if (group) {\n    group.classList.add(\"ts-hidden\");\n    group.setAttribute(\"aria-hidden\", \"true\");\n    group.style.display = \"none\";\n  }\n\n  updatePanelDataToggleVisibility();\n}\n  \n  \n  \n  \n  function chooseDistributionCabinets(requiredSlots, catalog) {\n  var need = Math.max(0, Math.round(toNumber(requiredSlots) || 0));\n  if (!(need > 0)) return [];\n\n  var items = Array.isArray(catalog) ? catalog : [];\n  var caps = items.length ? items.map(function(x){ return x.cap; }) : [15, 8, 5];\n\n  var best = null;\n\n  var max15 = Math.ceil(need \/ 15) + 2;\n  var max8  = Math.ceil(need \/ 8) + 2;\n  var max5  = Math.ceil(need \/ 5) + 2;\n\n  for (var q15 = 0; q15 <= max15; q15++) {\n    for (var q8 = 0; q8 <= max8; q8++) {\n      for (var q5 = 0; q5 <= max5; q5++) {\n        var sum = q15 * 15 + q8 * 8 + q5 * 5;\n        if (sum < need) continue;\n\n        var over = sum - need;\n        var qty = q15 + q8 + q5;\n\n        var candidate = {\n          sum: sum,\n          over: over,\n          qty: qty,\n          q15: q15,\n          q8: q8,\n          q5: q5\n        };\n\n        if (!best) { best = candidate; continue; }\n\n        if (candidate.over < best.over) { best = candidate; continue; }\n        if (candidate.over > best.over) continue;\n\n        if (candidate.qty < best.qty) { best = candidate; continue; }\n        if (candidate.qty > best.qty) continue;\n\n        if (candidate.q15 > best.q15) { best = candidate; continue; }\n        if (candidate.q15 < best.q15) continue;\n        if (candidate.q8 > best.q8) { best = candidate; continue; }\n      }\n    }\n  }\n\n  if (!best) return [];\n\n  var out = [];\n  if (best.q15 > 0) out.push({ cap: 15, qty: best.q15 });\n  if (best.q8  > 0) out.push({ cap: 8, qty: best.q8 });\n  if (best.q5  > 0) out.push({ cap: 5, qty: best.q5 });\n\n  return out;\n}\n\n\n\n\nfunction updateLastVisibleResultDivider() {\n  var box = byId(\"sysconfResultLinesBox\");\n  if (!box) return;\n\n  var lines = Array.prototype.slice.call(\n    box.querySelectorAll(\".sso-result-line\")\n  );\n\n  lines.forEach(function (row) {\n    row.classList.remove(\"is-last-visible\");\n    row.style.borderBottom = \"\";\n  });\n\n  var visible = lines.filter(function (row) {\n    return row.offsetParent !== null;\n  });\n\n  if (!visible.length) return;\n\n  var last = visible[visible.length - 1];\n  last.classList.add(\"is-last-visible\");\n  last.style.borderBottom = \"0\";\n}\n\n\n\n  function normalizeName(s) {\n    return String(s || \"\").toLowerCase().trim();\n  }\n\n\n  function getProductName(p) {\n    if (!p) return \"\";\n    return String(\n      p.sysconf_Produktnamn ||\n      p.sysconf_produktnamn ||\n      p.product_name ||\n      p.name ||\n      p.title ||\n      p.modell ||\n      \"\"\n    );\n  }\n  \n  function sanitizeRackModelName(name) {\n  var s = String(name || \"\").trim();\n  if (!s) return s;\n\n  s = s.replace(\/\\s+(ink|inkl)\\b.*$\/i, \"\").trim();\n\n  return s;\n}\n\n  function fallbackFindLikelyArticleNumber(obj) {\n    if (!obj) return \"\";\n    var best = \"\";\n    try {\n      Object.keys(obj).forEach(function (k) {\n        var v = obj[k];\n        if (v === null || v === undefined) return;\n        var s = String(v).trim();\n        if (!s) return;\n\n        var digits = s.replace(\/[^0-9]\/g, \"\");\n        if (digits.length >= 6 && digits.length <= 10) {\n          if (!best) best = s;\n          if (\/^[0-9]{6,10}$\/.test(s)) best = s;\n        }\n      });\n    } catch (e) {}\n    return best;\n  }\n\n  function pickStringValue(v) {\n    if (v === null || v === undefined) return \"\";\n    if (typeof v === \"string\" || typeof v === \"number\") return String(v).trim();\n\n    if (typeof v === \"object\") {\n      var keys = [\"value\", \"raw\", \"val\", \"text\"];\n      for (var i = 0; i < keys.length; i++) {\n        if (v[keys[i]] !== undefined && v[keys[i]] !== null) {\n          var s = String(v[keys[i]]).trim();\n          if (s) return s;\n        }\n      }\n    }\n    return \"\";\n  }\n\n  function getEnrFromAny(obj) {\n    if (!obj) return \"\";\n\n    var directKeys = [\n      \"sysconf_artnr\", \"sysconf_Artnr\",\n      \"sysconf_Enr\", \"sysconf_enr\",\n      \"enr\",\n      \"item_number\", \"itemNumber\",\n      \"article_number\", \"articleNumber\",\n      \"artikelnummer\",\n      \"articleNo\", \"art_no\", \"artNo\",\n      \"e_number\", \"eNumber\",\n      \"ean\"\n    ];\n\n    for (var i = 0; i < directKeys.length; i++) {\n      var key = directKeys[i];\n      if (obj[key] !== undefined) {\n        var s = pickStringValue(obj[key]);\n        if (s) return s;\n      }\n    }\n\n    var nested = obj.meta || obj.data || obj.fields || obj.field || null;\n    if (nested) {\n      for (var j = 0; j < directKeys.length; j++) {\n        var key2 = directKeys[j];\n        if (nested[key2] !== undefined) {\n          var s2 = pickStringValue(nested[key2]);\n          if (s2) return s2;\n        }\n      }\n    }\n\n    try {\n      var keysAll = Object.keys(obj);\n      for (var k = 0; k < keysAll.length; k++) {\n        var kName = keysAll[k];\n        if (!kName) continue;\n        if (String(kName).toLowerCase().indexOf(\"enr\") === -1 &&\n            String(kName).toLowerCase().indexOf(\"artnr\") === -1) continue;\n        var s3 = pickStringValue(obj[kName]);\n        if (s3) return s3;\n      }\n    } catch (e) {}\n\n    return \"\";\n  }\n\n  function getProductEnr(p) {\n    if (!p) return \"\";\n    var artnr = String(\n      p.sysconf_artnr ||\n      p.sysconf_Artnr ||\n      p.artnr ||\n      \"\"\n    ).trim();\n\n    if (artnr) return artnr;\n\n    var enr = String(\n      p.sysconf_enr ||\n      p.sysconf_Enr ||\n      p.enr ||\n      p.item_number ||\n      p.itemNumber ||\n      p.article_number ||\n      p.articleNumber ||\n      p.articleNo ||\n      p.art_no ||\n      p.artNo ||\n      \"\"\n    ).trim();\n\n    if (enr) return enr;\n\n    return getEnrFromAny(p);\n  }\n\n  function getProductPowerKw(p) {\n    if (!p) return NaN;\n    return toNumber(p.max_power || p.power_kw || p.power || p.kw);\n  }\n\n  function getSelectedOptionText(selectEl) {\n    if (!selectEl || !selectEl.options || selectEl.selectedIndex < 0) return \"\";\n    var opt = selectEl.options[selectEl.selectedIndex];\n    return opt ? String(opt.textContent || \"\").trim() : \"\";\n  }\n  \n  \n  \nfunction getSelectedBatteryPowerKw() {\n  var rawVal = elNumEso && elNumEso.value != null ? String(elNumEso.value).trim() : \"\";\n  var valNum = toNumber(rawVal);\n\n  if (isFinite(valNum) && valNum > 3) return valNum;\n\n  var txt = getSelectedOptionText(elNumEso);\n  if (txt) {\n    var m = txt.match(\/([0-9]+(?:[.,][0-9]+)?)\\s*kW\/i);\n    if (m && m[1]) {\n      var parsed = toNumber(m[1]);\n      if (isFinite(parsed) && parsed > 0) return parsed;\n    }\n  }\n\n  return NaN;\n}\n\nfunction parseKwFromOptionText(text) {\n  var s = String(text || \"\");\n  var m = s.match(\/([0-9]+(?:[.,][0-9]+)?)\\s*kW\/i);\n  if (!m || !m[1]) return NaN;\n  return toNumber(m[1]);\n}\n\nfunction getAllEsoKwOptions() {\n  if (!elNumEso || !elNumEso.options || !elNumEso.options.length) return [];\n\n  var vals = [];\n  for (var i = 0; i < elNumEso.options.length; i++) {\n    var opt = elNumEso.options[i];\n    if (!opt) continue;\n\n    var kw = parseKwFromOptionText(opt.textContent || opt.text || \"\");\n    if (isFinite(kw) && kw > 0) vals.push(kw);\n  }\n\n  vals.sort(function (a, b) { return a - b; });\n  var unique = [];\n  for (var j = 0; j < vals.length; j++) {\n    if (!unique.length || Math.abs(unique[unique.length - 1] - vals[j]) > 1e-9) unique.push(vals[j]);\n  }\n\n  return unique;\n}\n\nfunction isHighEsoSelection(selectedKw) {\n  var kw = toNumber(selectedKw);\n  if (!isFinite(kw) || kw <= 0) return false;\n\n  var all = getAllEsoKwOptions();\n  if (!all.length) return false;\n\n  var min = all[0];\n  var max = all[all.length - 1];\n\n  if (Math.abs(max - min) < 1e-9) return false;\n\n  if (Math.abs(kw - max) < 1e-9) return true;\n\n  if (Math.abs(kw - min) < 1e-9) return false;\n\n  var mid = (min + max) \/ 2;\n  return kw > mid;\n}\n\n\n\nfunction setSolarHiddenClassOnResultBox(solarVisible) {\n  var box = byId(\"sysconfResultLinesBox\");\n  if (box) box.classList.toggle(\"sysconf-solar-hidden\", !solarVisible);\n\n  var card = byId(\"sysconfResult\");\n  if (card) card.classList.toggle(\"sysconf-solar-hidden\", !solarVisible);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n  \/* =========================================================\n     SSO distribution\n  ========================================================= *\/\n  function getIntegerDistribution(total, groups) {\n    var t = Math.round(toNumber(total));\n    var g = Math.round(toNumber(groups));\n    if (!(t > 0 && g > 0)) return null;\n\n    var floorVal = Math.floor(t \/ g);\n    var remainder = t % g;\n\n    return {\n      total: t,\n      groups: g,\n      floorPanels: floorVal,\n      ceilPanels: floorVal + 1,\n      remainder: remainder\n    };\n  }\n\nfunction renderSsoDistributionLines(dist) {\n  var container = byId(\"sysconfDistributionLines\");\n  if (!container) return;\n\n  while (container.firstChild) container.removeChild(container.firstChild);\n  if (!dist) return;\n\n  var groups = dist.groups;\n  var floorPanels = dist.floorPanels;\n  var ceilPanels = dist.ceilPanels;\n  var remainder = dist.remainder;\n\n  var ceilCount = remainder;\n  var floorCount = groups - ceilCount;\n\n  function makeLine(startIdx, endIdx, panels) {\n    if (startIdx > endIdx) return null;\n\n    var label = (startIdx === endIdx)\n      ? (\"Recommended string allocation SSO \" + startIdx)\n      : (\"Recommended string allocation SSO \" + startIdx + \"-\" + endIdx);\n\n    var row = document.createElement(\"div\");\n    row.className = \"sso-result-line sysconf-dist-row\";\n\n    var left = document.createElement(\"div\");\n    left.className = \"sysconf-dist-left\";\n    left.textContent = label;\n\n    var right = document.createElement(\"div\");\n    right.className = \"sysconf-dist-right\";\n    right.textContent = panels + \" panels\";\n\n    row.appendChild(left);\n    row.appendChild(right);\n\n    return row;\n  }\n\n  if (floorCount > 0) {\n    var a = makeLine(1, floorCount, floorPanels);\n    if (a) container.appendChild(a);\n  }\n\n  if (ceilCount > 0) {\n    var b = makeLine(floorCount + 1, groups, ceilPanels);\n    if (b) container.appendChild(b);\n  }\n}\n\n\n  \/* =========================================================\n     Battery helpers\n  ========================================================= *\/\nfunction calculateNumBatterySystems(modulesTotal) {\n  var m = Math.round(toNumber(modulesTotal));\n  if (!(m > 0)) return 0;\n\n  return Math.ceil(m \/ 6);\n}\n\nfunction getEsoPerSystemByRules(systems, selectedKw) {\n  var high = isHighEsoSelection(selectedKw);\n\n  return high ? 2 : 1;\n}\n\n\n\nfunction calculateTotalEsoQty(modulesTotal, batteryPowerSelectedKw) {\n  var systems = calculateNumBatterySystems(modulesTotal);\n  if (!(systems > 0)) return 0;\n\n  var esoPerSystem = getEsoPerSystemByRules(systems, batteryPowerSelectedKw);\n  return systems * esoPerSystem;\n}\n\n  function calculateBatteryPower(energyKwh) {\n    var e = toNumber(energyKwh);\n    if (!(e > 0)) return NaN;\n    return e;\n  }\n\n  function findSso8kWProduct() {\n    for (var i = 0; i < products.length; i++) {\n      var p = products[i];\n      var n = normalizeName(getProductName(p));\n      if (n.indexOf(\"sso\") !== -1 && n.indexOf(\"8\") !== -1) return p;\n    }\n    return null;\n  }\n\n  function findProductByNameIncludes(tokens) {\n    var t = Array.isArray(tokens) ? tokens : [];\n    var best = null;\n    for (var i = 0; i < products.length; i++) {\n      var p = products[i];\n      var n = normalizeName(getProductName(p));\n      if (!n) continue;\n      var ok = true;\n      for (var j = 0; j < t.length; j++) {\n        if (n.indexOf(String(t[j]).toLowerCase()) === -1) { ok = false; break; }\n      }\n      if (ok) { best = p; break; }\n    }\n    return best;\n  }\n\n  function findSysconfProductByNameTokens(tokens) {\n    var t = Array.isArray(tokens) ? tokens : [];\n    for (var i = 0; i < products.length; i++) {\n      var p = products[i];\n      var n = normalizeName(getProductName(p));\n      if (!n) continue;\n\n      var ok = true;\n      for (var j = 0; j < t.length; j++) {\n        if (n.indexOf(String(t[j]).toLowerCase()) === -1) { ok = false; break; }\n      }\n      if (ok) return p;\n    }\n    return null;\n  }\n\n  function findSysconfProductByTokenSets(tokenSets) {\n    var sets = Array.isArray(tokenSets) ? tokenSets : [];\n    for (var i = 0; i < sets.length; i++) {\n      var p = findSysconfProductByNameTokens(sets[i]);\n      if (p) return p;\n    }\n    return null;\n  }\n\n  function findPowerCaseProduct() {\n    return findProductByNameIncludes([\"powercase\"]) || null;\n  }\n  \n  function parseDistributionCapacityFromName(name) {\n  var s = String(name || \"\").toLowerCase();\n  var m = s.match(\/power\\s*distribution\\s*([0-9]+)\/i);\n  if (m && m[1]) return parseInt(m[1], 10);\n  return NaN;\n}\n\nfunction findPowerDistributionProductByCapacity(cap) {\n  var c = String(cap);\n  return findSysconfProductByNameTokens([\"power\", \"distribution\", c]) || null;\n}\n\nfunction getPowerDistributionCatalog() {\n  var out = [];\n\n  for (var i = 0; i < products.length; i++) {\n    var p = products[i];\n    if (!p || !p.name) continue;\n\n    var name = String(p.name).toLowerCase();\n\n    if (name === \"power distribution 5\") {\n      out.push({ cap: 5, product: p });\n    } else if (name === \"power distribution 8\") {\n      out.push({ cap: 8, product: p });\n    } else if (name === \"power distribution 15\") {\n      out.push({ cap: 15, product: p });\n    }\n  }\n\n  return out;\n}\n\n  function findEsoProduct() {\n    var p = findProductByNameIncludes([\"eso\"]) || null;\n    if (!p) p = findProductByNameIncludes([\"energy\", \"storage\", \"optimizer\"]) || null;\n    return p;\n  }\n\n  function findBatterySubProduct(selectedBattery, kind) {\n    if (!selectedBattery) return null;\n\n    var list =\n      (Array.isArray(selectedBattery.sub_products) && selectedBattery.sub_products) ||\n      (Array.isArray(selectedBattery.subProducts) && selectedBattery.subProducts) ||\n      (Array.isArray(selectedBattery.parts) && selectedBattery.parts) ||\n      [];\n\n    function getName(x) {\n      return String((x && (x.name || x.product_name || x.title || x.modell)) || \"\").trim();\n    }\n\n    function pickFirstNonEmpty(obj, keys) {\n      if (!obj) return \"\";\n      for (var i = 0; i < keys.length; i++) {\n        var k = keys[i];\n        var v = obj[k];\n        if (v !== null && v !== undefined) {\n          var s = String(v).trim();\n          if (s) return s;\n        }\n      }\n      return \"\";\n    }\n\n    function getArticleNumber(x) {\n      if (!x) return \"\";\n\n      var direct = pickFirstNonEmpty(x, [\n        \"sysconf_Enr\", \"sysconf_enr\",\n        \"enr\",\n        \"e_number\", \"eNumber\",\n        \"e_nummer\", \"eNummer\",\n        \"item_number\", \"itemNumber\",\n        \"article_number\", \"articleNumber\",\n        \"artikelnummer\", \"articleNo\", \"art_no\", \"artNo\",\n        \"ean\"\n      ]);\n      if (direct) return direct;\n\n      var nested = x.meta || x.data || x.fields || null;\n      var nestedVal = pickFirstNonEmpty(nested, [\n        \"sysconf_Enr\", \"sysconf_enr\",\n        \"enr\",\n        \"e_number\", \"eNumber\",\n        \"e_nummer\", \"eNummer\",\n        \"item_number\", \"itemNumber\",\n        \"article_number\", \"articleNumber\",\n        \"artikelnummer\", \"articleNo\", \"art_no\", \"artNo\",\n        \"ean\"\n      ]);\n      if (nestedVal) return nestedVal;\n\n      return fallbackFindLikelyArticleNumber(x);\n    }\n\n    function isMatch(nameLower) {\n      if (kind === \"module\") return nameLower.indexOf(\"module\") !== -1 || nameLower.indexOf(\"modul\") !== -1;\n      if (kind === \"controller\") return nameLower.indexOf(\"controller\") !== -1 || nameLower.indexOf(\"kontroller\") !== -1 || nameLower.indexOf(\"bms\") !== -1;\n      return false;\n    }\n\n    for (var i = 0; i < list.length; i++) {\n      var sp = list[i];\n      var n = normalizeName(getName(sp));\n      if (!n) continue;\n      if (!isMatch(n)) continue;\n\n      return {\n        name: getName(sp),\n        enr: getArticleNumber(sp)\n      };\n    }\n\n    return null;\n  }\n\n  \/* =========================================================\n     Solar rules and EnergyHub selection\n  ========================================================= *\/\n  var LIMIT_VMP_LOW = 100;\n  var LIMIT_VMP_HIGH_BASE = 720;\n  var LIMIT_VOC_MAX_BASE = 1000;\n  var LIMIT_IMP_NO_LIMIT = 12.5;\n  var LIMIT_IMP_REDUCE_UNTIL = 14;\n  var LIMIT_IMP_MAX = 16;\n  var LIMIT_VOC_MAX_REDUCED = 720;\n  var LIMIT_IMP_REDUCE_STEP_A = 0.1;\n  var LIMIT_IMP_REDUCE_STEP_V = 8;\n  \n  \n  \n\n  function applyImpRules(imp) {\n    var vmpHigh = LIMIT_VMP_HIGH_BASE;\n    var vocMax = LIMIT_VOC_MAX_BASE;\n\n    if (!isFinite(imp)) return { vmpHigh: vmpHigh, vocMax: vocMax };\n    if (imp > LIMIT_IMP_MAX) return { vmpHigh: vmpHigh, vocMax: vocMax };\n\n    if (imp > LIMIT_IMP_NO_LIMIT) {\n      var reduceAmps = Math.min(imp, LIMIT_IMP_REDUCE_UNTIL) - LIMIT_IMP_NO_LIMIT;\n      if (reduceAmps < 0) reduceAmps = 0;\n\n      var steps = Math.ceil((reduceAmps \/ LIMIT_IMP_REDUCE_STEP_A) - 1e-9);\n      if (steps < 0) steps = 0;\n\n      vmpHigh = LIMIT_VMP_HIGH_BASE - (LIMIT_IMP_REDUCE_STEP_V * steps);\n      if (vmpHigh < 0) vmpHigh = 0;\n    }\n\n    if (imp > LIMIT_IMP_REDUCE_UNTIL && imp <= LIMIT_IMP_MAX) {\n      vocMax = LIMIT_VOC_MAX_REDUCED;\n    }\n\n    return { vmpHigh: vmpHigh, vocMax: vocMax };\n  }\n\n  function mountDelta(mountType) {\n    if (mountType === \"tak\") return 5;\n    if (mountType === \"fasad\") return 10;\n    return 0;\n  }\n\n  function isWallProduct(p) {\n    var n = normalizeName(getProductName(p));\n    if (n.indexOf(\"rack\") !== -1 || n.indexOf(\"cabinet\") !== -1) return false;\n    if (n.indexOf(\"wall\") !== -1) return true;\n\n    var isEnergyHub = (n.indexOf(\"energyhub\") !== -1);\n    var is14 = (\/(^|[^0-9])14([^0-9]|$)\/.test(n));\n    var isXl = (n.indexOf(\" xl \") !== -1 || n.endsWith(\" xl\") || n.indexOf(\"xl \") !== -1);\n\n    if (isEnergyHub && is14 && !isXl) return true;\n    return false;\n  }\n\n  function isXlProduct(p) {\n    var n = normalizeName(getProductName(p));\n    var hasXl = \/(^|[^a-z0-9])xl([^a-z0-9]|$)\/.test(n) || n.indexOf(\" xl \") !== -1 || n.indexOf(\"xl \") !== -1;\n    return hasXl && n.indexOf(\"rack\") === -1;\n  }\n\n  function getVariantFromName(productName) {\n    var n = normalizeName(productName);\n    if (\/(^|[^0-9])28([^0-9]|$)\/.test(n)) return 28;\n    if (\/(^|[^0-9])21([^0-9]|$)\/.test(n)) return 21;\n    return null;\n  }\n\n  function getRackUFromName(nameOrProductName) {\n    var n = normalizeName(nameOrProductName);\n    if (n.indexOf(\"42u\") !== -1) return 42;\n    if (n.indexOf(\"24u\") !== -1) return 24;\n    return null;\n  }\n\n  function findBestWall(requiredKw, productsArr) {\n    var walls = (productsArr || [])\n      .filter(function (p) { return p && isWallProduct(p); })\n      .slice()\n      .sort(function (a, b) { return getProductPowerKw(a) - getProductPowerKw(b); });\n\n    for (var i = 0; i < walls.length; i++) {\n      var cap = getProductPowerKw(walls[i]);\n      if (isFinite(cap) && cap > 0 && requiredKw <= cap + 1e-6) return walls[i];\n    }\n    return walls.length ? walls[walls.length - 1] : null;\n  }\n\n  function findXlProduct(productsArr, variant) {\n    for (var i = 0; i < (productsArr || []).length; i++) {\n      var p = productsArr[i];\n      if (!p || !isXlProduct(p)) continue;\n      if (getVariantFromName(getProductName(p)) === variant) return p;\n    }\n    return null;\n  }\n\n  function findRackProduct(productsArr, rackU, baseVariant) {\n    for (var i = 0; i < (productsArr || []).length; i++) {\n      var p = productsArr[i];\n      if (!p) continue;\n      var name = getProductName(p);\n      var n = normalizeName(name);\n      var hasU = (getRackUFromName(name) === rackU);\n      var isRackOrCabinet = (n.indexOf(\"rack\") !== -1 || n.indexOf(\"cabinet\") !== -1);\n      if (!hasU || !isRackOrCabinet) continue;\n      var v = getVariantFromName(name);\n      if (v !== null && v !== baseVariant) continue;\n      return p;\n    }\n    return null;\n  }\n\n  function getWall28CapFallback(productsArr) {\n    var w28 = (productsArr || []).find(function (p) {\n      var n = normalizeName(getProductName(p));\n      return n.indexOf(\"wall\") !== -1 && getVariantFromName(getProductName(p)) === 28;\n    });\n    var cap = w28 ? getProductPowerKw(w28) : NaN;\n    return (isFinite(cap) && cap > 0) ? cap : 33.6;\n  }\n\n  function getMaxCalculatorHubCapKw(productsArr) {\n    var xl28 = findXlProduct(productsArr, 28);\n    if (!xl28) return NaN;\n    var xlPower28 = getProductPowerKw(xl28);\n    if (!isFinite(xlPower28) || xlPower28 <= 0) return NaN;\n    return 5 * xlPower28;\n  }\n\n  function buildRackPlan(requiredKw, productsArr) {\n    var xl21 = findXlProduct(productsArr, 21);\n    var xl28 = findXlProduct(productsArr, 28);\n\n    var xl21Power = xl21 ? getProductPowerKw(xl21) : NaN;\n    var xl28Power = xl28 ? getProductPowerKw(xl28) : NaN;\n\n    var has21 = xl21 && isFinite(xl21Power) && xl21Power > 0;\n    var has28 = xl28 && isFinite(xl28Power) && xl28Power > 0;\n    if (!has21 && !has28) return null;\n\n    var best = null;\n\n    function considerCandidate(candidate) {\n      if (!candidate) return;\n      if (!best) { best = candidate; return; }\n\n      if (candidate.overKw < best.overKw - 1e-6) { best = candidate; return; }\n      if (best.overKw < candidate.overKw - 1e-6) return;\n\n      if (candidate.totalXl < best.totalXl) { best = candidate; return; }\n      if (best.totalXl < candidate.totalXl) return;\n\n      if (candidate.rackU < best.rackU) { best = candidate; return; }\n      if (best.rackU < candidate.rackU) return;\n\n      if (candidate.extraXl28Qty < best.extraXl28Qty) { best = candidate; return; }\n      if (best.extraXl28Qty < candidate.extraXl28Qty) return;\n\n      best = candidate;\n    }\n\n    var rackOptions = [\n      { rackU: 24, slots: 3 },\n      { rackU: 42, slots: 5 }\n    ];\n\n    rackOptions.forEach(function (ro) {\n      [21, 28].forEach(function (baseVariant) {\n        var rackProduct = findRackProduct(productsArr, ro.rackU, baseVariant);\n        if (!rackProduct) return;\n\n        var basePower = (baseVariant === 21) ? (has21 ? xl21Power : NaN) : (has28 ? xl28Power : NaN);\n        if (!isFinite(basePower) || basePower <= 0) return;\n\n        for (var totalXl = 1; totalXl <= ro.slots; totalXl++) {\n          var extras = totalXl - 1;\n          for (var extra28 = 0; extra28 <= extras; extra28++) {\n            var extra21 = extras - extra28;\n\n            if (extra21 > 0 && !has21) continue;\n            if (extra28 > 0 && !has28) continue;\n\n            var provided = basePower + (extra21 * (has21 ? xl21Power : 0)) + (extra28 * (has28 ? xl28Power : 0));\n            if (!isFinite(provided) || provided <= 0) continue;\n            if (provided + 1e-6 < requiredKw) continue;\n\n            considerCandidate({\n              rackU: ro.rackU,\n              rackSlots: ro.slots,\n              rackProduct: rackProduct,\n              baseVariant: baseVariant,\n              xl21Product: xl21 || null,\n              xl28Product: xl28 || null,\n              totalXl: totalXl,\n              extraXl21Qty: extra21,\n              extraXl28Qty: extra28,\n              providedKw: provided,\n              overKw: provided - requiredKw\n            });\n          }\n        }\n      });\n    });\n\n    return best;\n  }\n\nfunction buildRackModulesText(rackPlan) {\n  if (!rackPlan) return \"\";\n\n  var totalXl = Math.max(0, toNumber(rackPlan.totalXl) || 0);\n  if (totalXl <= 0) return \"\";\n\n  var baseVariant = rackPlan.baseVariant;\n  var extra21 = Math.max(0, toNumber(rackPlan.extraXl21Qty) || 0);\n  var extra28 = Math.max(0, toNumber(rackPlan.extraXl28Qty) || 0);\n\n  var count21 = (baseVariant === 21) ? (1 + extra21) : extra21;\n  var count28 = (baseVariant === 28) ? (1 + extra28) : extra28;\n\n  var parts = [];\n  if (count21 > 0) parts.push(count21 + \" pcs XL 21 kW\");\n  if (count28 > 0) parts.push(count28 + \" pcs XL 28 kW\");\n\n  return parts.join(\", \");\n}\n\nfunction setRackModulesRowVisible(visible) {\n  var row = byId(\"sysconfRackModulesRow\");\n  if (!row) return;\n  row.style.display = visible ? \"\" : \"none\";\n}\n\nfunction setSolarTechVisible(visible) {\n  if (!elSolarTechToggleBtn || !elSolarTechCard || !elSolarTechToggleText) return;\n\n  var open = !!visible;\n\n  elSolarTechToggleBtn.setAttribute(\"aria-expanded\", open ? \"true\" : \"false\");\n\n  elSolarTechCard.setAttribute(\"aria-hidden\", open ? \"false\" : \"true\");\n  elSolarTechCard.classList.toggle(\"ts-hidden\", !open);\n\n  elSolarTechToggleText.textContent = open ? \"Hide technical details\" : \"Show technical details\";\n}\n\n\n\n\n\n\n\n\n  \/* =========================================================\n     Validation and button\n  ========================================================= *\/\n  var hasCalculated = false;\n  var calcSolarEnabled = true;\n  var calcBatteryEnabled = true;\n  var solarComputed = false;\n\nfunction validateBeforeCalculate() {\n  hideCalcAlert();\n\n  var panelCount = toNumber(elNumPanels && elNumPanels.value);\n  var panelSelected = String(elPanelSelect && elPanelSelect.value || \"\");\n\n  var solarTouched =\n    (isFinite(panelCount) && panelCount > 0) ||\n    !!panelSelected;\n\n  if (solarTouched) {\n    if (!(isFinite(panelCount) && panelCount > 0) && !!panelSelected) {\n      showCalcAlert(\"Enter number of panels for the selected panel model.\");\n      return false;\n    }\n    if ((isFinite(panelCount) && panelCount > 0) && !panelSelected) {\n      showCalcAlert(\"Select panel model for the given number of panels.\");\n      return false;\n    }\n  }\n\n  var batterySelected = String(elBatterySelect && elBatterySelect.value || \"\");\n  var esoSelected = String(elNumEso && elNumEso.value || \"\");\n\n  var batteryTouched = !!batterySelected || !!esoSelected;\n\n  if (batteryTouched) {\n    if (!!batterySelected && !esoSelected) {\n      showCalcAlert(\"Select battery power for the chosen battery type.\");\n      return false;\n    }\n    if (!batterySelected && !!esoSelected) {\n      showCalcAlert(\"Select battery type for the chosen battery power.\");\n      return false;\n    }\n  }\n\n  var cableToggleEl = document.getElementById(\"tsCableToggle\");\n  var cableEnabled = !!(cableToggleEl && cableToggleEl.checked);\n\n  if (!solarTouched && !batteryTouched && !cableEnabled) {\n    showCalcAlert(\"Select at least one part to calculate: solar, battery or cabling.\");\n    return false;\n  }\n\n  if (cableEnabled && !solarTouched && !batteryTouched) {\n    showCalcAlert(\"Cabling is enabled, but neither solar nor battery is included. Select solar and\/or battery for a complete system design.\");\n    return false;\n  }\n\n  calcSolarEnabled = !!solarTouched;\n  calcBatteryEnabled = !!batteryTouched;\n\n  return true;\n}\n\n\n\n\n  \n\n  function scrollToResults() {\n    var target = elAfterCalc || elResultBox;\n    if (!target) return;\n    requestAnimationFrame(function () {\n      requestAnimationFrame(function () {\n        try { target.scrollIntoView({ behavior: \"smooth\", block: \"start\" }); }\n        catch (e) {\n          var y = target.getBoundingClientRect().top + window.pageYOffset;\n          window.scrollTo(0, y);\n        }\n      });\n    });\n  }\n\n  function bindInvalidate(el, ev) {\n    if (!el) return;\n    el.addEventListener(ev, function () { invalidateCalculation(); });\n  }\n\n  function calculateSystem() {\n    var solarValid = false;\n    var batteryValid = false;\n    \n    var articles = [];\n    \n    var data = window.toolSuiteData || {};\nvar products = Array.isArray(data.sysconfProducts) ? data.sysconfProducts : [];\n    \n    var numPanels = NaN;\nvar baseMinTemp = NaN;\nvar baseMaxTemp = NaN;\n\nvar powerCaseQty = 0;\n\n    var ssoCount = NaN;\n    var minPanelsPerSso = NaN;\n    var maxPanelsPerSso = NaN;\n    var installedKwPmax = NaN;\n    var batteryPowerKwp = NaN;\n    var hubPowerBasisKwp = NaN;\n\n    var dist = null;\n    var panel = null;\n\n    var stringVmpNomWorst = NaN;\n    var ssoVmpMinWorst = NaN;\n    var ssoVmpMaxWorst = NaN;\n    var stringVocColdWorst = NaN;\n\n    var imp = NaN;\n    var isc = NaN;\n\n    if (calcSolarEnabled) {\n      panel = buildPanelForCalculation();\n      numPanels = toNumber(elNumPanels && elNumPanels.value);\n\n      if (panel && isFinite(numPanels) && numPanels > 0) {\n        var vmp = toNumber(panel.vmp);\n        var voc = toNumber(panel.voc);\n        imp = toNumber(panel.imp);\n        isc = toNumber(panel.isc);\n        var coeff = toNumber(panel.voc_temp_coeff);\n        var pmax = toNumber(panel.pmax);\n\n        if (isFinite(vmp) && vmp > 0 && isFinite(voc) && voc > 0 && isFinite(imp) && imp > 0) {\n          var limits = applyImpRules(imp);\n          var currentVmpHigh = limits.vmpHigh;\n          var currentVocMax = limits.vocMax;\n\n          minPanelsPerSso = Math.max(1, Math.ceil(LIMIT_VMP_LOW \/ vmp));\n          \nif (isFinite(numPanels) && numPanels > 0 && isFinite(minPanelsPerSso) && minPanelsPerSso > 0) {\n  if (numPanels < minPanelsPerSso) {\n    showCalcAlert(\n      \"Number of panels is below the minimum number per SSO. Enter at least \" + minPanelsPerSso + \" panels or change panel model.\"\n    );\n    solarValid = false;\n    dist = null;\n    return { ok: false };\n  }\n}\n\n          baseMinTemp = toNumber(elMinTemp && elMinTemp.value);\nbaseMaxTemp = toNumber(elMaxTemp && elMaxTemp.value);\n          var delta = mountDelta(String(elMountType && elMountType.value || \"\"));\n\n          var minTemp = isFinite(baseMinTemp) ? baseMinTemp + delta : NaN;\n          var maxTemp = isFinite(baseMaxTemp) ? baseMaxTemp + delta : NaN;\n\n          var k = isFinite(coeff) ? (coeff \/ 100) : 0;\n          var tRef = 25;\n\n          var dTcold = isFinite(minTemp) ? (minTemp - tRef) : 0;\n          var dThot = isFinite(maxTemp) ? (maxTemp - tRef) : 0;\n\n          var panelVmpCold = vmp * (1 + k * dTcold);\n          var panelVmpHot = vmp * (1 + k * dThot);\n          var panelVmpMax = Math.max(panelVmpCold, panelVmpHot);\n\n          var panelVocCold = voc * (1 + k * dTcold);\n\n          var maxPanelsNom = Math.floor(currentVmpHigh \/ vmp);\n          var maxPanelsVmpMax = Math.floor(currentVmpHigh \/ panelVmpMax);\n          var maxPanelsVoc = Math.floor(currentVocMax \/ panelVocCold);\n\n          maxPanelsPerSso = Math.min(maxPanelsNom, maxPanelsVmpMax, maxPanelsVoc);\n          if (!isFinite(maxPanelsPerSso) || maxPanelsPerSso < 1) maxPanelsPerSso = NaN;\n\n          var impOk = isFinite(imp) && imp <= LIMIT_IMP_MAX;\n\n          if (isFinite(maxPanelsPerSso) && maxPanelsPerSso >= 1 && impOk) {\n            var recommendedSso = Math.ceil(numPanels \/ maxPanelsPerSso);\n            dist = getIntegerDistribution(numPanels, recommendedSso);\n\n            if (dist) {\n              ssoCount = recommendedSso;\n\n              var panelsPerSsoWorst = dist.ceilPanels;\n\n              stringVmpNomWorst = vmp * panelsPerSsoWorst;\n\n              var stringVmpColdWorst = panelVmpCold * panelsPerSsoWorst;\n              var stringVmpHotWorst = panelVmpHot * panelsPerSsoWorst;\n\n              ssoVmpMinWorst = Math.min(stringVmpColdWorst, stringVmpHotWorst);\n              ssoVmpMaxWorst = Math.max(stringVmpColdWorst, stringVmpHotWorst);\n\n              stringVocColdWorst = panelVocCold * panelsPerSsoWorst;\n\n              if (isFinite(pmax) && pmax > 0) installedKwPmax = (pmax * Math.round(numPanels)) \/ 1000;\n\n              solarValid = true;\n\n              if (elResVmpNominal) elResVmpNominal.textContent = isFinite(stringVmpNomWorst) ? formatNumber(stringVmpNomWorst, 0) + \" V\" : \"-\";\n              if (elResVmpMin) elResVmpMin.textContent = isFinite(ssoVmpMinWorst) ? formatNumber(ssoVmpMinWorst, 0) + \" V\" : \"-\";\n              if (elResVmpMax) elResVmpMax.textContent = isFinite(ssoVmpMaxWorst) ? formatNumber(ssoVmpMaxWorst, 0) + \" V\" : \"-\";\n              if (elResVocMax) elResVocMax.textContent = isFinite(stringVocColdWorst) ? formatNumber(stringVocColdWorst, 0) + \" V\" : \"-\";\n              if (elResImp) elResImp.textContent = isFinite(imp) ? formatNumber(imp, 1) + \" A\" : \"-\";\n              if (elResIsc) elResIsc.textContent = isFinite(isc) ? formatNumber(isc, 1) + \" A\" : \"-\";\n            }\n          }\n        }\n      }\n    }\n    \n    window.__sysconfLastSolar = {\n  ok: !!solarValid,\n  panel: solarValid ? (panel || null) : null,\n  numPanels: isFinite(numPanels) ? Math.round(numPanels) : null,\n  mountType: String(elMountType && elMountType.value || \"\"),\n  minTemp: isFinite(baseMinTemp) ? baseMinTemp : null,\n  maxTemp: isFinite(baseMaxTemp) ? baseMaxTemp : null\n};\n\n\nvar selectedBattery = null;\nvar batteryEnergyKwh = NaN;\n\nvar batteryPowerSelectedKw = NaN;\n\nvar esoQtyPerSystem = 1;\nvar totalEsoQty = NaN;\nvar systems = 0;\nvar modules = NaN;\n\nvar batteryForHub = false;\nvar batteryForArticles = false;\n\nif (calcBatteryEnabled) {\n  selectedBattery = batteryMap[String(elBatterySelect && elBatterySelect.value || \"\")] || null;\n\n  if (selectedBattery) {\n    batteryEnergyKwh = toNumber(selectedBattery.energy_kwh);\n\n    batteryPowerSelectedKw = getSelectedBatteryPowerKw();\n\n    if (isFinite(batteryPowerSelectedKw) && batteryPowerSelectedKw > 0) {\n      batteryForHub = true;\n      batteryPowerKwp = batteryPowerSelectedKw;\n    }\n\n    modules = toNumber(selectedBattery.modules);\n    systems = calculateNumBatterySystems(modules);\n\n    esoQtyPerSystem =\n      toNumber(selectedBattery.eso_per_system) ||\n      toNumber(selectedBattery.esoPerSystem) ||\n      toNumber(selectedBattery.eso_qty) ||\n      toNumber(selectedBattery.esoQty) ||\n      1;\n\n    esoQtyPerSystem = (isFinite(esoQtyPerSystem) && esoQtyPerSystem > 0) ? Math.round(esoQtyPerSystem) : 1;\n\n    totalEsoQty = calculateTotalEsoQty(modules, batteryPowerSelectedKw);\n\n    batteryForArticles = (isFinite(systems) && systems > 0 && isFinite(modules) && modules > 0);\n  }\n}\n\nbatteryValid = batteryForArticles;\n\n\n    if (!solarValid && !batteryValid) return { ok: false };\n\nif (solarValid && isFinite(installedKwPmax) && installedKwPmax > 0) {\n  hubPowerBasisKwp = installedKwPmax;\n}\n\nsolarComputed = !!(calcSolarEnabled && solarValid);\n\n\n\nsetSolarTechToggleRowVisible(!!solarComputed);\nsetSolarTechVisible(false);\n    if (batteryForHub && isFinite(batteryPowerKwp) && batteryPowerKwp > 0) {\n  hubPowerBasisKwp = isFinite(hubPowerBasisKwp) ? Math.max(hubPowerBasisKwp, batteryPowerKwp) : batteryPowerKwp;\n}\n\n\n    var rackPlan = null;\n    var energyHubProduct = null;\n    var isOversizeConfig = false;\n\n    if (isFinite(hubPowerBasisKwp) && hubPowerBasisKwp > 0) {\n      var wall28Cap = getWall28CapFallback(products);\n      var maxCalcCap = getMaxCalculatorHubCapKw(products);\n\n      if (isFinite(maxCalcCap) && hubPowerBasisKwp > maxCalcCap + 1e-6) {\n        isOversizeConfig = true;\n      } else if (hubPowerBasisKwp > wall28Cap + 1e-6) {\n        rackPlan = buildRackPlan(hubPowerBasisKwp, products);\n        if (!rackPlan) isOversizeConfig = true;\n      } else {\n        energyHubProduct = findBestWall(hubPowerBasisKwp, products);\n      }\n    }\n\n   \n    if (elAfterCalc) elAfterCalc.style.display = \"\";\n    if (elResultBox) elResultBox.style.display = \"\";\n\nsetSolarResultVisible(!!solarValid);\nsetSolarHiddenClassOnResultBox(!!solarValid);\nupdateLastVisibleResultDivider();\n\nif (calcBatteryEnabled && batteryValid) {\n  var batteryText = getSelectedOptionText(elBatterySelect);\n  var powerText = getSelectedOptionText(elNumEso);\n  var combined = batteryText;\n  if (powerText) combined += \" \/ \" + powerText;\n  setTextSafe(elResBatterySummary, combined);\n  setBatteryResultVisible(true);\n} else {\n  setBatteryResultVisible(false);\n}\n\nupdateLastVisibleResultDivider();\n\nif (!solarComputed) {\n  setSolarTechToggleRowVisible(false);\n  setSolarTechVisible(false);\n}\n    \n\nif (solarValid) {\n  if (elResInstalled) elResInstalled.textContent = isFinite(installedKwPmax) ? (formatNumber(installedKwPmax, 1) + \" kW\") : \"-\";\n  if (elResNumSso) elResNumSso.textContent = isFinite(ssoCount) ? (ssoCount + \" pcs\") : \"-\";\n\n  if (elResMinMaxPanels) {\n    var minTxt = isFinite(minPanelsPerSso) ? String(minPanelsPerSso) : \"-\";\n    var maxTxt = isFinite(maxPanelsPerSso) ? String(maxPanelsPerSso) : \"-\";\n    elResMinMaxPanels.textContent = (minTxt + \"\/\" + maxTxt + \" pcs\");\n  }\n\n  renderSsoDistributionLines(dist);\n}\n\n    if (isOversizeConfig) {\n      setTextSafe(elResEnergyHubModel, \"Contact Ferroamp for EnergyHub system design.\");\n      setRackModulesRowVisible(false);\n      var rackMods = byId(\"sysconfResRackModules\");\n      if (rackMods) rackMods.textContent = \"\";\n    } else if (rackPlan) {\n      setTextSafe(elResEnergyHubModel, sanitizeRackModelName(getProductName(rackPlan.rackProduct)) || \"-\");\n\n      var modulesText = buildRackModulesText(rackPlan);\n      var rackModsEl = byId(\"sysconfResRackModules\");\n      if (rackModsEl) rackModsEl.textContent = modulesText || \"\";\n      setRackModulesRowVisible(!!modulesText);\n    } else {\n      setTextSafe(elResEnergyHubModel, getProductName(energyHubProduct) || \"-\");\n      setRackModulesRowVisible(false);\n      var rackModsEl2 = byId(\"sysconfResRackModules\");\n      if (rackModsEl2) rackModsEl2.textContent = \"\";\n    }\n\n\n\n\n    if (isOversizeConfig) {\n      articles.push({ qty: 1, enr: \"\", name: \"Contact Ferroamp for EnergyHub system design.\" });\n    } else if (rackPlan) {\n      articles.push({ qty: 1, enr: getProductEnr(rackPlan.rackProduct), name: getProductName(rackPlan.rackProduct) || \"EnergyHub Rack\" });\n\n      if ((rackPlan.extraXl21Qty || 0) > 0) {\n        articles.push({ qty: rackPlan.extraXl21Qty, enr: getProductEnr(rackPlan.xl21Product), name: getProductName(rackPlan.xl21Product) || \"EnergyHub XL 21 kW\" });\n      }\n      if ((rackPlan.extraXl28Qty || 0) > 0) {\n        articles.push({ qty: rackPlan.extraXl28Qty, enr: getProductEnr(rackPlan.xl28Product), name: getProductName(rackPlan.xl28Product) || \"EnergyHub XL 28 kW\" });\n      }\n    } else if (energyHubProduct) {\n      articles.push({ qty: 1, enr: getProductEnr(energyHubProduct), name: getProductName(energyHubProduct) || \"EnergyHub\" });\n    }\n\n    if (calcSolarEnabled && solarValid) {\n      if (isFinite(ssoCount) && ssoCount > 0) {\n        var ssoProduct = findSso8kWProduct();\n        articles.push({\n          qty: ssoCount,\n          enr: getProductEnr(ssoProduct),\n          name: getProductName(ssoProduct) || \"SSO 8 kW\"\n        });\n      }\n    }\n\nif (calcBatteryEnabled && batteryValid && selectedBattery) {\n  var modules = toNumber(selectedBattery.modules);\n\n  var controllers = systems;\n\n  var moduleProduct = findBatterySubProduct(selectedBattery, \"module\");\n  var controllerProduct = findBatterySubProduct(selectedBattery, \"controller\");\n\n  var sysconfH3Module = findSysconfProductByTokenSets([\n    [\"pylontech\", \"force\", \"h3\", \"module\"],\n    [\"pylontech\", \"force\", \"h3\", \"modul\"],\n    [\"force\", \"h3\", \"module\"],\n    [\"force\", \"h3\", \"modul\"]\n  ]);\n\n  var sysconfH3Controller = findSysconfProductByTokenSets([\n    [\"pylontech\", \"force\", \"h3\", \"controller\"],\n    [\"pylontech\", \"force\", \"h3\", \"kontroller\"],\n    [\"pylontech\", \"force\", \"h3\", \"bms\"],\n    [\"force\", \"h3\", \"controller\"],\n    [\"force\", \"h3\", \"kontroller\"],\n    [\"force\", \"h3\", \"bms\"]\n  ]);\n\n  if (isFinite(controllers) && controllers > 0) {\n    var controllerEnr = (sysconfH3Controller ? getProductEnr(sysconfH3Controller) : (controllerProduct && controllerProduct.enr ? controllerProduct.enr : \"\"));\n    var controllerName = (sysconfH3Controller ? getProductName(sysconfH3Controller) : (controllerProduct && controllerProduct.name ? controllerProduct.name : (selectedBattery.name + \" battery controller\")));\n\n    articles.push({ qty: controllers, enr: controllerEnr, name: controllerName });\n  }\n\n  if (isFinite(modules) && modules > 0) {\n    var moduleEnr = (sysconfH3Module ? getProductEnr(sysconfH3Module) : (moduleProduct && moduleProduct.enr ? moduleProduct.enr : \"\"));\n    var moduleName = (sysconfH3Module ? getProductName(sysconfH3Module) : (moduleProduct && moduleProduct.name ? moduleProduct.name : (selectedBattery.name + \" battery module\")));\n\n    articles.push({ qty: modules, enr: moduleEnr, name: moduleName });\n  }\n\n  powerCaseQty = 0;\n  if (isFinite(controllers) && controllers > 0) powerCaseQty = controllers;\n\n  var powerCaseProduct = findPowerCaseProduct();\n  if (isFinite(systems) && systems > 0) {\n    articles.push({\n      qty: controllers,\n      enr: getProductEnr(powerCaseProduct),\n      name: getProductName(powerCaseProduct) || \"PowerCase\"\n    });\n  }\n\n  var esoProduct = findEsoProduct();\n  if (esoProduct && isFinite(totalEsoQty) && totalEsoQty > 0) {\n    articles.push({ qty: totalEsoQty, enr: getProductEnr(esoProduct), name: getProductName(esoProduct) || \"ESO\" });\n  }\n}\n\nvar totalSso = (isFinite(ssoCount) && ssoCount > 0) ? Math.round(ssoCount) : 0;\n\nvar slotsPerPowerCase = 3;\nvar powerCaseSlots = (powerCaseQty > 0) ? (powerCaseQty * slotsPerPowerCase) : 0;\n\nvar remainingSlots = Math.max(0, totalSso - powerCaseSlots);\n\nif (remainingSlots > 0) {\n  var catalog = getPowerDistributionCatalog();\n  var selected = chooseDistributionCabinets(remainingSlots, catalog);\n\n  for (var i = 0; i < selected.length; i++) {\n    var cap = selected[i].cap;\n    var qty = selected[i].qty;\n\n    var prod = null;\n    for (var j = 0; j < catalog.length; j++) {\n      if (catalog[j].cap === cap) {\n        prod = catalog[j].product;\n        break;\n      }\n    }\n\n    articles.push({\n      qty: qty,\n      enr: prod ? getProductEnr(prod) : \"\",\n      name: prod ? prod.name : (\"Power Distribution \" + cap)\n    });\n  }\n}\n\n\nrenderArticles(articles);\n\nreturn {\n  ok: true,\n  installedKw: installedKwPmax,\n  hubBasisKw: hubPowerBasisKwp,\n  hub: energyHubProduct || (rackPlan ? rackPlan.rackProduct : null),\n  battery: selectedBattery || null,\n  batteryKw: batteryPowerKwp,\n  articles: articles\n};\n  }\n  \n  \n  \n\n\n  \/* =========================================================\n     Init UI state\n  ========================================================= *\/\ninitPanelSelect();\ninitBatterySelect();\nhandlePanelSelectionChange();\nhideAllResults();\ninitSolarTechToggle();              \nsetSolarTechToggleRowVisible(false); \nsetSolarTechVisible(false);          \nsetDocumentationVisible(false);\n\n\n  if (elPanelSelect) elPanelSelect.addEventListener(\"change\", function () { handlePanelSelectionChange(); invalidateCalculation(); });\n  if (elBatterySelect) elBatterySelect.addEventListener(\"change\", function () { invalidateCalculation(); });\n\n  bindInvalidate(elNumPanels, \"input\");\n  bindInvalidate(elMountType, \"change\");\n  bindInvalidate(elManualModel, \"input\");\n\n  bindInvalidate(elBatterySelect, \"change\");\n  bindInvalidate(elNumEso, \"change\");\n  bindInvalidate(elNumEso, \"input\");\n\n  if (elCalcBtn) {\n    elCalcBtn.addEventListener(\"click\", function () {\n      hasCalculated = false;\n      hideCalcAlert();\n\n      if (!validateBeforeCalculate()) return;\n\n      var cableToggleEl = document.getElementById(\"tsCableToggle\");\nvar cableEnabled = !!(cableToggleEl && cableToggleEl.checked);\n\n      if (cableEnabled) {\n        setCableExpanded(true, { scroll: false });\n\n        var v0 = cableModule.validateForSystem();\n        if (!v0.ok) {\n          showCalcAlert(v0.message || \"Please fill in all required fields for the cable calculation.\");\n          hideAllResults();\n          clearCableInSystemResult();\n          return;\n        }\n      }\n\n      var sys = calculateSystem();\n      if (!sys || !sys.ok) {\n        hideAllResults();\n        clearCableInSystemResult();\n        return;\n      }\n\nif (cableEnabled) {\n  var v = cableModule.validateForSystem();\n  if (!v.ok) {\n    showCalcAlert(v.message || \"Please fill in all required fields for the cable calculation.\");\n    clearCableInSystemResult();\n    hideAllResults();\n    return;\n  }\n\nvar ok = cableModule.calculate();\nif (!ok) {\n  var ce = window.__cableLastError || {};\n  var code = String(ce.code || \"\");\n  var msg = (ce && ce.message) ? ce.message : \"The cable calculation could not be completed. Check the entered values.\";\n\n  showCalcAlert(msg);\n  clearCableInSystemResult();\n  setDocumentationVisible(false);\n  hasCalculated = false;\n\n  if (code === \"oversize\") {\n    hideAllResults();\n    return;\n  }\n\n  return;\n}\n\n  showCableInSystemResult(window.__cableLastResult || { ok: false });\n} else {\n  clearCableInSystemResult();\n}\n\n      syncDocumentationCableFields();\n      hasCalculated = true;\n      setDocumentationVisible(true);\n      scrollToResults();\n    });\n  }\n\n  if (elForm) elForm.addEventListener(\"submit\", function (e) { e.preventDefault(); });\n\n  return true;\n};\n\nfunction safeFileToken(str) {\n  if (str == null) return \"\";\n  var s = String(str).trim();\n\n  s = s\n    .replace(\/[\u00e5\u00c5]\/g, \"a\")\n    .replace(\/[\u00e4\u00c4]\/g, \"a\")\n    .replace(\/[\u00f6\u00d6]\/g, \"o\")\n    .replace(\/[^a-zA-Z0-9]+\/g, \"_\")\n    .replace(\/^_+|_+$\/g, \"\")\n    .replace(\/_+\/g, \"_\");\n\n  return s;\n}\n\nfunction todayYyyyMmDd() {\n  var dt = new Date();\n  var yy = dt.getFullYear();\n  var mm = String(dt.getMonth() + 1).padStart(2, \"0\");\n  var dd = String(dt.getDate()).padStart(2, \"0\");\n  return \"\" + yy + mm + dd;\n}\n\nfunction buildPdfFilename(prefix, projectName) {\n  var dateToken = todayYyyyMmDd();\n  var proj = safeFileToken(projectName);\n\n  var base = prefix + \"_\" + dateToken;\n  if (proj) base += \"_\" + proj;\n\n  return base + \".pdf\";\n}\n\n\n\/* =========================================================\n   PDF export: bind + generator\n========================================================= *\/\n\nfunction isPdfVisible(el) {\n  if (!el) return false;\n  var cs = window.getComputedStyle(el);\n  return cs.display !== \"none\" && cs.visibility !== \"hidden\" && cs.opacity !== \"0\";\n}\n\nfunction updatePdfCardDividers(pdfRoot) {\n  if (!pdfRoot) return;\n\n  var cards = pdfRoot.querySelectorAll(\".tsPdfCard\");\n  for (var c = 0; c < cards.length; c++) {\n    var lines = Array.prototype.slice.call(cards[c].querySelectorAll(\".tsPdfLine\"));\n\n    for (var i = 0; i < lines.length; i++) {\n      lines[i].style.borderBottom = \"\";\n    }\n\n    var visible = [];\n    for (var j = 0; j < lines.length; j++) {\n      if (isPdfVisible(lines[j])) visible.push(lines[j]);\n    }\n\n    if (visible.length) {\n      visible[visible.length - 1].style.borderBottom = \"0\";\n    }\n  }\n}\n\n\nfunction populatePdfValuesFromUi(pdfRoot) {\n  function setTextById(pdfId, uiEl) {\n    var pdfEl = pdfRoot.querySelector(\"#\" + pdfId);\n    if (!pdfEl) return;\n    pdfEl.textContent = uiEl ? String(uiEl.textContent || \"\").trim() : \"-\";\n  }\n\n  var projectInput = document.getElementById(\"tsProjectName\");\n  var pdfProjectName = pdfRoot.querySelector(\"#pdfProjectName\");\n  if (pdfProjectName) pdfProjectName.textContent = projectInput && projectInput.value ? String(projectInput.value).trim() : \"-\";\n\n  var pdfDate = pdfRoot.querySelector(\"#pdfDate\");\n  if (pdfDate) {\n    var d = new Date();\n    var yyyy = d.getFullYear();\n    var mm = String(d.getMonth() + 1).padStart(2, \"0\");\n    var dd = String(d.getDate()).padStart(2, \"0\");\n    pdfDate.textContent = yyyy + \"-\" + mm + \"-\" + dd;\n  }\n\n  setTextById(\"pdfHubModel\", document.getElementById(\"sysconfResEnergyHubModel\"));\n  setTextById(\"pdfBattery\", document.getElementById(\"sysconfResBatterySummary\"));\n  setTextById(\"pdfSolarInstalled\", document.getElementById(\"sysconfResInstalledPower\"));\n  setTextById(\"pdfNumSso\", document.getElementById(\"sysconfResNumSso\"));\n  setTextById(\"pdfMinMaxPanelsPerSso\", document.getElementById(\"sysconfResMinMaxPanelsPerSso\"));\n\n  var uiRackModulesRow = document.getElementById(\"sysconfRackModulesRow\");\n  var pdfRackModulesRow = pdfRoot.querySelector(\"#pdfRackModulesRow\");\n  if (pdfRackModulesRow) pdfRackModulesRow.style.display = isUiVisible(uiRackModulesRow) ? \"\" : \"none\";\n\n  setTextById(\"pdfRackModules\", document.getElementById(\"sysconfResRackModules\"));\n\n  setTextById(\"pdfVmpNominal\", document.getElementById(\"sysconfResVmpNominal\"));\n  setTextById(\"pdfVmpMin\", document.getElementById(\"sysconfResVmpMin\"));\n  setTextById(\"pdfVmpMax\", document.getElementById(\"sysconfResVmpMax\"));\n  setTextById(\"pdfVocMax\", document.getElementById(\"sysconfResVocMax\"));\n  setTextById(\"pdfImp\", document.getElementById(\"sysconfResImp\"));\n  setTextById(\"pdfIsc\", document.getElementById(\"sysconfResIsc\"));\n\n  var pdfDist = pdfRoot.querySelector(\"#pdfDistributionLines\");\n  var uiDist = document.getElementById(\"sysconfDistributionLines\");\n  if (pdfDist) {\n    pdfDist.innerHTML = \"\";\n    if (uiDist) {\n      var rows = uiDist.querySelectorAll(\".sso-result-line\");\n      for (var i = 0; i < rows.length; i++) {\n        var left = rows[i].querySelector(\".sysconf-dist-left\");\n        var right = rows[i].querySelector(\".sysconf-dist-right\");\n\n        var line = document.createElement(\"div\");\n        line.className = \"tsPdfLine\";\n        var label = document.createElement(\"div\");\n        label.className = \"tsPdfLabel\";\n        label.textContent = left ? String(left.textContent || \"\").trim() : \"\";\n\n        var val = document.createElement(\"div\");\n        val.className = \"tsPdfValue\";\n        val.textContent = right ? String(right.textContent || \"\").trim() : \"\";\n\n        line.appendChild(label);\n        line.appendChild(val);\n        pdfDist.appendChild(line);\n      }\n    }\n  }\n\n  var pdfArticlesBody = pdfRoot.querySelector(\"#pdfArticlesBody\");\n  var uiArticlesLines = document.getElementById(\"sysconfArticlesLines\");\n  if (pdfArticlesBody) {\n    pdfArticlesBody.innerHTML = \"\";\n    if (uiArticlesLines) {\n      var uiRows = uiArticlesLines.querySelectorAll(\".sysconf-articles-row\");\n      for (var j = 0; j < uiRows.length; j++) {\n        var qty = uiRows[j].querySelector(\".sysconf-col-qty\");\n        var enr = uiRows[j].querySelector(\".sysconf-col-enr\");\n        var name = uiRows[j].querySelector(\".sysconf-col-name\");\n\n        var r = document.createElement(\"div\");\n        r.className = \"tsPdfArticlesRow\";\n\n        var c1 = document.createElement(\"div\");\n        c1.className = \"tsPdfColQty\";\n        c1.textContent = qty ? String(qty.textContent || \"\").trim() : \"\";\n\n        var c2 = document.createElement(\"div\");\n        c2.className = \"tsPdfColEnr\";\n        c2.textContent = enr ? String(enr.textContent || \"\").trim() : \"\";\n\n        var c3 = document.createElement(\"div\");\n        c3.className = \"tsPdfColName\";\n        c3.textContent = name ? String(name.textContent || \"\").trim() : \"\";\n\n        r.appendChild(c1);\n        r.appendChild(c2);\n        r.appendChild(c3);\n        pdfArticlesBody.appendChild(r);\n      }\n    }\n  }\n\n  setTextById(\"pdfCableA\", document.getElementById(\"sysconfResCableA\"));\n  setTextById(\"pdfCableB\", document.getElementById(\"sysconfResCableB\"));\n  setTextById(\"pdfCableTotal\", document.getElementById(\"sysconfResCableTotal\"));\n\n(function setCableSystemVoltage() {\n  var el = pdfRoot.querySelector(\"#pdfSystemVoltage\");\n  if (!el) return;\n\n  var txt = (window.__cableSystemVoltageText || \"\").trim();\n  el.textContent = txt ? txt : \"-\";\n\n  var row = pdfRoot.querySelector(\"#pdfCableLineSystemVoltage\");\n  if (row) row.style.display = txt ? \"\" : \"none\";\n})();\n  \n  \n  \n  function readValue(el) {\n  if (!el) return \"\";\n  if (typeof el.value === \"string\") return String(el.value || \"\").trim();\n  return String(el.textContent || \"\").trim();\n}\n\nfunction firstNonEmpty(values) {\n  for (var i = 0; i < values.length; i++) {\n    var s = String(values[i] || \"\").trim();\n    if (s) return s;\n  }\n  return \"\";\n}\n\nfunction getCableNameFromUi(which) {\n  var scope = (function () {\n    return (\n      document.querySelector(\"#tsCableSectionSystem #kabelkalkylatorPrint\") ||\n      document.getElementById(\"kabelkalkylatorPrint\") ||\n      document\n    );\n  })();\n\n  var nameEl1 = document.getElementById(which === \"A\" ? \"tsCableNameA\" : \"tsCableNameB\");\n  var nameEl2 = document.getElementById(which === \"A\" ? \"cableNameA\" : \"cableNameB\");\n  var nameEl3 = scope && scope.querySelector(which === \"A\" ? \"#cableNameA\" : \"#cableNameB\");\n\n  return firstNonEmpty([\n    readValue(nameEl1),\n    readValue(nameEl2),\n    readValue(nameEl3)\n  ]);\n}\n\n(function applyCableLabelsToPdf() {\n  var hasCableResult = !!(window.__cableLastResult && window.__cableLastResult.ok);\n  if (!hasCableResult) return;\n\n  var labelA = pdfRoot.querySelector(\"#pdfCableLabelA\");\n  var labelB = pdfRoot.querySelector(\"#pdfCableLabelB\");\n\n  var nameA = getCableNameFromUi(\"A\");\n  var nameB = getCableNameFromUi(\"B\");\n\n  if (labelA) labelA.textContent = nameA ? nameA : \"Cable A\";\n  if (labelB) labelB.textContent = nameB ? nameB : \"Cable B\";\n})();\n\n  \n  \n   var uiPanelModel = document.getElementById(\"sysconfPanelSelect\");\n  var uiPanelCount = document.getElementById(\"sysconfNumPanels\");\n  var uiMountType  = document.getElementById(\"sysconfMountType\");\n  var uiMinTemp    = document.getElementById(\"sysconfMinTemperature\");\n  var uiMaxTemp    = document.getElementById(\"sysconfMaxTemperature\");\n\n  function setPdfText(id, value) {\n    var el = pdfRoot.querySelector(\"#\" + id);\n    if (!el) return;\n    var s = (value == null) ? \"\" : String(value).trim();\n    el.textContent = s ? s : \"-\";\n  }\n\n  function selectedText(selectEl) {\n    if (!selectEl || selectEl.selectedIndex < 0) return \"\";\n    var opt = selectEl.options[selectEl.selectedIndex];\n    return opt ? String(opt.textContent || \"\").trim() : \"\";\n  }\n\n  setPdfText(\"pdfPanelModel\", selectedText(uiPanelModel));\n  setPdfText(\"pdfPanelCount\", uiPanelCount ? uiPanelCount.value : \"\");\n  setPdfText(\"pdfMountType\", selectedText(uiMountType));\n  setPdfText(\"pdfMinTemp\", uiMinTemp ? uiMinTemp.value : \"\");\n  setPdfText(\"pdfMaxTemp\", uiMaxTemp ? uiMaxTemp.value : \"\");\n\n  setPdfText(\"pdfPanelPmax\", (document.getElementById(\"sysconfPanelPmax\") || {}).value);\n  setPdfText(\"pdfPanelVmp\",  (document.getElementById(\"sysconfPanelVmp\")  || {}).value);\n  setPdfText(\"pdfPanelVoc\",  (document.getElementById(\"sysconfPanelVoc\")  || {}).value);\n  setPdfText(\"pdfPanelImp\",  (document.getElementById(\"sysconfPanelImp\")  || {}).value);\n  setPdfText(\"pdfPanelIsc\",  (document.getElementById(\"sysconfPanelIsc\")  || {}).value);\n  setPdfText(\"pdfPanelVocCoeff\", (document.getElementById(\"sysconfPanelVocCoeff\") || {}).value);\n\n  var lastSolar = window.__sysconfLastSolar || {};\n  var panelObj = lastSolar.panel || null;\n\n  if (panelObj) {\n    setPdfText(\"pdfPanelPmax\", isFinite(panelObj.pmax) ? String(panelObj.pmax) : \"-\");\n    setPdfText(\"pdfPanelVmp\", isFinite(panelObj.vmp) ? String(panelObj.vmp) : \"-\");\n    setPdfText(\"pdfPanelVoc\", isFinite(panelObj.voc) ? String(panelObj.voc) : \"-\");\n    setPdfText(\"pdfPanelImp\", isFinite(panelObj.imp) ? String(panelObj.imp) : \"-\");\n    setPdfText(\"pdfPanelIsc\", isFinite(panelObj.isc) ? String(panelObj.isc) : \"-\");\n    setPdfText(\"pdfPanelVocCoeff\", isFinite(panelObj.voc_temp_coeff) ? String(panelObj.voc_temp_coeff) : \"-\");\n  }\n  \nfunction getCableScope() {\n  return (\n    document.querySelector(\"#tsCableSectionSystem #kabelkalkylatorPrint\") ||\n    document.getElementById(\"kabelkalkylatorPrint\")\n  );\n}\n\nfunction getCableUiEl(selector) {\n  var scope = getCableScope();\n  if (!scope) return null;\n  return scope.querySelector(selector);\n}\n\nfunction getSelectedText(selectEl) {\n  if (!selectEl || selectEl.selectedIndex < 0) return \"\";\n  var opt = selectEl.options[selectEl.selectedIndex];\n  return opt ? String(opt.textContent || \"\").trim() : \"\";\n}\n\nfunction readCheckedCalcMode() {\n  var scope = getCableScope();\n  if (!scope) return \"fromLoad\";\n  var radios = scope.querySelectorAll('input[name=\"calc_mode\"]');\n  for (var i = 0; i < radios.length; i++) {\n    if (radios[i] && radios[i].checked) return String(radios[i].value || \"fromLoad\");\n  }\n  return \"fromLoad\";\n}\n\nfunction joinInline(parts) {\n  var clean = [];\n  for (var i = 0; i < (parts || []).length; i++) {\n    var s = (parts[i] == null) ? \"\" : String(parts[i]).trim();\n    if (s) clean.push(s);\n  }\n  return clean.join(\", \");\n}\n\nfunction buildCableInlineInputsText(suffix) {\n  var suf = suffix || \"\";\n  var mode = readCheckedCalcMode();\n  var isFromCableMode = (mode === \"fromCable\");\n\n  var powerEl  = getCableUiEl(suf ? \"#power\" + suf : \"#power\");\n  var lengthEl = getCableUiEl(suf ? \"#length\" + suf : \"#length\");\n  var dropEl   = getCableUiEl(suf ? \"#maxDrop\" + suf : \"#maxDrop\");\n  var tempEl   = getCableUiEl(suf ? \"#ambientTemp\" + suf : \"#ambientTemp\");\n\n  var installEl = getCableUiEl(\"#installMethod\");\n  var insulationEl = getCableUiEl(\"#insulationType\");\n\n  var modeText = isFromCableMode ? \"Existing cable\" : \"New cable\";\n\n  var knownCableText = \"\";\n  if (!suf && isFromCableMode) {\n    var knownCableSel = getCableUiEl(\"#knownCableTypeA\");\n    var t = getSelectedText(knownCableSel);\n    if (t) knownCableText = \"Selection: \" + t;\n  }\n\n  function valWithUnit(el, unit) {\n    if (!el) return \"\";\n    var v = String(el.value || \"\").trim();\n    if (!v) return \"\";\n    return v + (unit ? (\" \" + unit) : \"\");\n  }\n\n  var parts = [];\n  parts.push(modeText);\n  if (knownCableText) parts.push(knownCableText);\n\n  parts.push(valWithUnit(powerEl, \"kW\"));\n  parts.push(valWithUnit(lengthEl, \"m\"));\n\n  parts.push(dropEl ? (\"Max \" + valWithUnit(dropEl, \"%\")) : \"\");\n  parts.push(tempEl ? (valWithUnit(tempEl, \"\u00b0C\")) : \"\");\n\n  var instTxt = getSelectedText(installEl);\n  if (instTxt) parts.push(instTxt);\n\n  var insTxt = getSelectedText(insulationEl);\n  if (insTxt) parts.push(insTxt);\n\n  return joinInline(parts);\n}\n\nfunction setInlinePdfText(id, text) {\n  var el = pdfRoot.querySelector(\"#\" + id);\n  if (!el) return;\n\n  var s = (text == null) ? \"\" : String(text).trim();\n  el.textContent = s ? s : \"\";\n  el.style.display = s ? \"\" : \"none\";\n}\n\n(function fillCableInlineInputs() {\n  var hasCableResult = !!(window.__cableLastResult && window.__cableLastResult.ok);\n  if (!hasCableResult) {\n    setInlinePdfText(\"pdfCableInputsInlineA\", \"\");\n    setInlinePdfText(\"pdfCableInputsInlineB\", \"\");\n    return;\n  }\n\n  setInlinePdfText(\"pdfCableInputsInlineA\", buildCableInlineInputsText(\"\"));\n\n  var seriesToggle = getCableUiEl(\"#seriesToggle\");\n  var seriesOn = !!(seriesToggle && seriesToggle.checked);\n\n  var res = window.__cableLastResult || {};\n  var hasB = !!String(res.bText || \"\").trim();\n\n  if (seriesOn && hasB) {\n    setInlinePdfText(\"pdfCableInputsInlineB\", buildCableInlineInputsText(\"2\"));\n  } else {\n    setInlinePdfText(\"pdfCableInputsInlineB\", \"\");\n  }\n})();\n\nfunction setPdfTextSafe(id, value, fallback) {\n  var el = pdfRoot.querySelector(\"#\" + id);\n  if (!el) return;\n  var s = (value == null) ? \"\" : String(value).trim();\n  el.textContent = s ? s : (fallback || \"-\");\n}\n\nfunction setPdfShowSafe(id, show) {\n  var el = pdfRoot.querySelector(\"#\" + id);\n  if (!el) return;\n  el.style.display = show ? \"\" : \"none\";\n}\n\nfunction cableSelectedText(sel) {\n  if (!sel || sel.selectedIndex < 0) return \"\";\n  var opt = sel.options[sel.selectedIndex];\n  return opt ? String(opt.textContent || \"\").trim() : \"\";\n}\n\n\n\n\n\nfunction fillCableInputsStructured() {\n  var hasCableResult = !!(window.__cableLastResult && window.__cableLastResult.ok);\n  if (!hasCableResult) return;\n\n  var scope =\n    document.querySelector(\"#tsCableSectionSystem #kabelkalkylatorPrint\") ||\n    document.getElementById(\"kabelkalkylatorPrint\");\n\n  if (!scope) return;\n\n  var res = window.__cableLastResult || {};\n\n  function q(id) { return scope.querySelector(\"#\" + id); }\n\n  function val(id, unit) {\n    var el = q(id);\n    var v = el ? String(el.value || \"\").trim() : \"\";\n    if (!v) return \"\";\n    return unit ? (v + \" \" + unit) : v;\n  }\n\n  function getCableName(inputId, fallback) {\n    var el = document.getElementById(inputId);\n    var v = el ? String(el.value || \"\").trim() : \"\";\n    return v || fallback;\n  }\n\n  function splitCableResult(text) {\n    var s = String(text || \"\").trim();\n    if (!s) return { material: \"-\", config: \"-\" };\n\n    var idx = s.indexOf(\",\");\n    if (idx === -1) return { material: s, config: \"-\" };\n\n    return {\n      material: s.slice(0, idx).trim() || \"-\",\n      config: s.slice(idx + 1).trim() || \"-\"\n    };\n  }\n\n  var seriesToggle = q(\"seriesToggle\");\n  var seriesOn = !!(seriesToggle && seriesToggle.checked);\n  var hasB = seriesOn && !!String(res.bText || \"\").trim();\n\n  var cableNameA = getCableName(\"tsCableNameA\", \"Cable A\");\n  var cableNameB = getCableName(\"tsCableNameB\", \"Cable B\");\n\n  setPdfTextSafe(\"pdfCableNameA\", cableNameA, \"Cable A\");\n  setPdfTextSafe(\"pdfCableResultNameA\", cableNameA, \"Cable A\");\n\n  if (hasB) {\n    setPdfTextSafe(\"pdfCableNameB\", cableNameB, \"Cable B\");\n    setPdfTextSafe(\"pdfCableResultNameB\", cableNameB, \"Cable B\");\n  }\n\n  var mode = (function () {\n    var radios = scope.querySelectorAll('input[name=\"calc_mode\"]');\n    for (var i = 0; i < radios.length; i++) {\n      if (radios[i] && radios[i].checked) return String(radios[i].value || \"fromLoad\");\n    }\n    return \"fromLoad\";\n  })();\n\n  var modeText = (mode === \"fromCable\") ? \"Existing cable\" : \"New cable\";\n  setPdfTextSafe(\"pdfCableModeA\", modeText, \"-\");\n\n  setPdfTextSafe(\"pdfCablePowerA\",  val(\"power\", \"kW\"), \"-\");\n  setPdfTextSafe(\"pdfCableLengthA\", val(\"length\", \"m\"), \"-\");\n  setPdfTextSafe(\"pdfCableDropA\",   val(\"maxDrop\", \"%\"), \"-\");\n  setPdfTextSafe(\"pdfCableTempA\",   val(\"ambientTemp\", \"\u00b0C\"), \"-\");\n  setPdfTextSafe(\"pdfCableInstallA\", cableSelectedText(q(\"installMethod\")), \"-\");\n  setPdfTextSafe(\"pdfCableInsulationA\", cableSelectedText(q(\"insulationType\")), \"-\");\n\n  var a = splitCableResult(res.aText);\n  setPdfTextSafe(\"pdfCableMaterialA\", a.material, \"-\");\n  setPdfTextSafe(\"pdfCableConfigA\", a.config, \"-\");\n\n  setPdfShowSafe(\"pdfCableGroupTitleB\", hasB);\n  setPdfShowSafe(\"pdfCableInputsB\", hasB);\n  setPdfShowSafe(\"pdfCableGroupB\", hasB);\n\n  if (hasB) {\n    setPdfTextSafe(\"pdfCableModeB\", modeText, \"-\");\n\n    setPdfTextSafe(\"pdfCablePowerB\",  val(\"power2\", \"kW\"), \"-\");\n    setPdfTextSafe(\"pdfCableLengthB\", val(\"length2\", \"m\"), \"-\");\n    setPdfTextSafe(\"pdfCableDropB\",   val(\"maxDrop2\", \"%\"), \"-\");\n    setPdfTextSafe(\"pdfCableTempB\",   val(\"ambientTemp2\", \"\u00b0C\"), \"-\");\n    setPdfTextSafe(\"pdfCableInstallB\", cableSelectedText(q(\"installMethod\")), \"-\");\n    setPdfTextSafe(\"pdfCableInsulationB\", cableSelectedText(q(\"insulationType\")), \"-\");\n\n    var b = splitCableResult(res.bText);\n    setPdfTextSafe(\"pdfCableMaterialB\", b.material, \"-\");\n    setPdfTextSafe(\"pdfCableConfigB\", b.config, \"-\");\n  }\n}\n\nfillCableInputsStructured();\n\n\n\n\n}\n\n\n\n\n\n\nfunction isUiVisible(el) {\n  if (!el) return false;\n  if (!el.isConnected) return false;\n  if (el.classList && el.classList.contains(\"ts-hidden\")) return false;\n  if (el.getAttribute && el.getAttribute(\"aria-hidden\") === \"true\") return false;\n\n  var cs = window.getComputedStyle(el);\n  if (!cs) return false;\n  return cs.display !== \"none\" && cs.visibility !== \"hidden\" && cs.opacity !== \"0\";\n}\n\nfunction setPdfDisplay(el, show) {\n  if (!el) return;\n  el.style.display = show ? \"\" : \"none\";\n}\n\nfunction applyPdfVisibilityFromUi(pdfRoot) {\n  var uiSolarBlock = document.getElementById(\"sysconfSolarBlock\");\n  var uiSolarSep   = document.getElementById(\"sysconfSolarSeparator\");\n  var uiBatteryRow = document.querySelector(\".sysconf-row-battery\");\n  var uiTechRow = document.getElementById(\"sysconfSolarTechToggleRow\");\n\n  var uiCableWrap      = document.getElementById(\"sysconfCableCardWrap\");\n  var uiCableLineA     = document.getElementById(\"sysconfCableLineA\");\n  var uiCableLineB     = document.getElementById(\"sysconfCableLineB\");\n  var uiCableLineTotal = document.getElementById(\"sysconfCableLineTotal\");\n\n  var pdfSolarBlock   = pdfRoot.querySelector(\"#pdfSolarBlock\");\n  var pdfSolarDivider = pdfRoot.querySelector(\"#pdfSolarDivider\");\n  var pdfBatteryRow   = pdfRoot.querySelector(\"#pdfBatteryRow\");\n\n  var pdfTechTitle = pdfRoot.querySelector(\"#pdfTechTitle\");\n  var pdfTechBlock = pdfRoot.querySelector(\"#pdfTechBlock\");\n\n  var pdfCableSection   = pdfRoot.querySelector(\"#pdfSectionCable\");\n  var pdfCableLineA     = pdfRoot.querySelector(\"#pdfCableLineA\");\n  var pdfCableLineB     = pdfRoot.querySelector(\"#pdfCableLineB\");\n  var pdfCableLineTotal = pdfRoot.querySelector(\"#pdfCableLineTotal\");\n\n  var showSolar  = isUiVisible(uiSolarBlock);\n  var showSolarSep = showSolar && isUiVisible(uiSolarSep);\n\n  var showBattery = isUiVisible(uiBatteryRow);\n\n  var lastSolar = window.__sysconfLastSolar || {};\n  var showTech = showSolar && !!lastSolar.ok;\n\n  var hasCableResult = !!(window.__cableLastResult && window.__cableLastResult.ok);\n  var showCable = isUiVisible(uiCableWrap) || hasCableResult;\n  var res = window.__cableLastResult || {};\n  var showCableA = showCable && !!String(res.aText || \"\").trim();\n  var showCableB = showCable && !!String(res.bText || \"\").trim();\n  var showCableT = showCable && !!String(res.totalText || \"\").trim();\n\n  setPdfDisplay(pdfSolarBlock, showSolar);\n  setPdfDisplay(pdfSolarDivider, showSolarSep);\n\n  setPdfDisplay(pdfBatteryRow, showBattery);\n\n  setPdfDisplay(pdfTechTitle, showTech);\n  setPdfDisplay(pdfTechBlock, showTech);\n\n  setPdfDisplay(pdfCableSection, showCable);\n  setPdfDisplay(pdfCableLineA, showCableA);\n  setPdfDisplay(pdfCableLineB, showCableB);\n  setPdfDisplay(pdfCableLineTotal, showCableT);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction bindPdfButton() {\n  var pdfBtn = document.getElementById(\"tsCreatePdfBtn\");\n  if (!pdfBtn) return;\n\n  if (pdfBtn.__tsPdfBound) return;\n  pdfBtn.__tsPdfBound = true;\n\npdfBtn.addEventListener(\"click\", function () {\n  if (pdfBtn.disabled || pdfBtn.__busy) return;\n  pdfBtn.__busy = true;\n\n  try {\n    var p = createSystemPdf();\n    Promise.resolve(p).finally(function () { pdfBtn.__busy = false; });\n  } catch (err) {\n    pdfBtn.__busy = false;\n    console.error(\"PDF export failed\", err);\n    alert(\"PDF could not be created. See console for details.\");\n  }\n});\n}\n\nfunction ensurePdfHost() {\n  var host = document.getElementById(\"tsSystemPdfHost\");\n  if (!host) {\n    host = document.createElement(\"div\");\n    host.id = \"tsSystemPdfHost\";\n    document.body.appendChild(host);\n  } else if (host.parentNode !== document.body) {\n    document.body.appendChild(host);\n\n  }\n\n  host.style.position = \"fixed\";\n  host.style.left = \"-10000px\";\n  host.style.top = \"0\";\n  host.style.width = \"794px\";\n  host.style.background = \"#fff\";\n  host.style.pointerEvents = \"none\";\n  host.style.zIndex = \"2147483647\";\n  host.style.opacity = \"1\";\n  host.style.display = \"block\";\n  host.style.visibility = \"visible\";\n\n  return host;\n}\n\n\n\n\n\n\n\n\n\n\nfunction createSystemPdf() {\n  if (typeof window.html2canvas !== \"function\") {\n    throw new Error(\"html2canvas is missing. Load html2canvas before PDF export.\");\n  }\n  var JsPdfCtor = (window.jspdf && window.jspdf.jsPDF) ? window.jspdf.jsPDF : window.jsPDF;\n  if (typeof JsPdfCtor !== \"function\") {\n    throw new Error(\"jsPDF is missing. Load jsPDF before PDF export.\");\n  }\n\n  var template = document.getElementById(\"sysconfPdfTemplate\");\n  if (!template) throw new Error(\"Cannot find #sysconfPdfTemplate in DOM.\");\n\n  var host = ensurePdfHost();\n  host.innerHTML = \"\";\n\n  function waitForImages(rootEl) {\n    var imgs = rootEl ? rootEl.querySelectorAll(\"img\") : [];\n    if (!imgs || !imgs.length) return Promise.resolve();\n\n    return Promise.all([].map.call(imgs, function (img) {\n      if (img.complete && img.naturalWidth > 0) return Promise.resolve();\n\n      return new Promise(function (resolve) {\n        var done = false;\n        function finish() { if (done) return; done = true; resolve(); }\n\n        img.addEventListener(\"load\", finish, { once: true });\n        img.addEventListener(\"error\", finish, { once: true });\n\n        setTimeout(finish, 3000);\n      });\n    }));\n  }\n  \n  function setPdfNotesVisible(pdfRoot, visible) {\n  if (!pdfRoot) return;\n  var notes = pdfRoot.querySelector(\"#systemPdfSectionNotes\");\n  if (notes) notes.style.display = visible ? \"\" : \"none\";\n}\n\n  function forcePdfLogo(pdfRoot) {\n    var img = pdfRoot.querySelector(\"#pdfBrandLogo\");\n    if (!img) return Promise.resolve();\n\n    var logoUrl = \"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png\";\n\n    img.removeAttribute(\"data-src\");\n    img.removeAttribute(\"data-lazy-src\");\n    img.removeAttribute(\"data-srcset\");\n    img.removeAttribute(\"data-lazy-srcset\");\n    img.removeAttribute(\"data-original\");\n    img.removeAttribute(\"data-original-src\");\n    img.removeAttribute(\"data-original-set\");\n    img.removeAttribute(\"srcset\");\n\n    img.crossOrigin = \"anonymous\";\n    img.referrerPolicy = \"no-referrer\";\n    img.src = logoUrl;\n\n    img.style.setProperty(\"display\", \"block\", \"important\");\n    img.style.setProperty(\"visibility\", \"visible\", \"important\");\n    img.style.setProperty(\"opacity\", \"1\", \"important\");\n\n    if (img.decode) {\n      return img.decode().catch(function () {\n        return new Promise(function (resolve) {\n          img.onload = function () { resolve(); };\n          img.onerror = function () { resolve(); };\n        });\n      });\n    }\n\n    return new Promise(function (resolve) {\n      if (img.complete && img.naturalWidth > 0) return resolve();\n      img.onload = function () { resolve(); };\n      img.onerror = function () { resolve(); };\n    });\n  }\n\n  function forceAllImages(pdfRoot) {\n    var imgs = Array.prototype.slice.call(pdfRoot.querySelectorAll(\"img\"));\n    var tasks = imgs.map(function (im) {\n      if (im.id === \"pdfBrandLogo\") return forcePdfLogo(pdfRoot);\n      return Promise.resolve();\n    });\n    return Promise.all(tasks);\n  }\n\n  function makePage() {\n    var page = document.createElement(\"div\");\n    page.style.width = \"794px\";\n    page.style.minHeight = \"1123px\";\n    page.style.background = \"#fff\";\n    page.style.pointerEvents = \"none\";\n    page.style.position = \"relative\";\n    page.style.left = \"0\";\n    page.style.top = \"0\";\n    page.style.padding = \"0\";\n    page.style.boxSizing = \"border-box\";\n    return page;\n  }\n\n  function cloneInto(page) {\n    var cloned = template.cloneNode(true);\n\n    cloned.classList.remove(\"ts-hidden\");\n    cloned.removeAttribute(\"aria-hidden\");\n\n    cloned.style.setProperty(\"display\", \"block\", \"important\");\n    cloned.style.setProperty(\"visibility\", \"visible\", \"important\");\n    cloned.style.setProperty(\"opacity\", \"1\", \"important\");\n\n    page.innerHTML = \"\";\n    page.appendChild(cloned);\n\n    return cloned;\n  }\n\n  function showOnly(root, idsToShow) {\n    var showSet = {};\n    for (var i = 0; i < idsToShow.length; i++) showSet[idsToShow[i]] = true;\n\n    var idsAll = [\"pdfSectionCore\", \"pdfSectionSolarTech\", \"pdfSectionArticles\", \"pdfSectionCable\"];\n    for (var j = 0; j < idsAll.length; j++) {\n      var el = root.querySelector(\"#\" + idsAll[j]);\n      if (!el) continue;\n      el.style.display = showSet[idsAll[j]] ? \"\" : \"none\";\n    }\n  }\n\n  function renderCanvas(targetEl) {\n    return waitForImages(targetEl).then(function () {\n      return window.html2canvas(targetEl, {\n        scale: 2,\n        useCORS: true,\n        backgroundColor: \"#ffffff\",\n        windowWidth: 794,\n        scrollX: 0,\n        scrollY: 0\n      });\n    });\n  }\n\n  function addCanvasAsPage(pdf, canvas, addNewPage) {\n    var imgData = canvas.toDataURL(\"image\/jpeg\", 0.92);\n    var pageWidth = pdf.internal.pageSize.getWidth();\n    var pageHeight = pdf.internal.pageSize.getHeight();\n\n    var imgWidth = pageWidth;\n    var imgHeight = (canvas.height * imgWidth) \/ canvas.width;\n\n    if (addNewPage) pdf.addPage();\n    pdf.addImage(imgData, \"JPEG\", 0, 0, imgWidth, imgHeight);\n  }\n  \n  \n\n  function cleanupHost() {\n    if (window.__tsKeepPdfHost) return;\n    host.innerHTML = \"\";\n  }\n\n  var page1 = makePage();\n  host.appendChild(page1);\nvar root1 = cloneInto(page1);\n\nsetPdfNotesVisible(root1, false);\n\nshowOnly(root1, [\"pdfSectionCore\", \"pdfSectionCable\", \"pdfSectionArticles\"]);\napplyPdfVisibilityFromUi(root1);\npopulatePdfValuesFromUi(root1);\nupdatePdfCardDividers(root1);\n\n  var lastSolar = window.__sysconfLastSolar || {};\n  var hasSolar = !!lastSolar.ok;\n\n  return forceAllImages(root1)\n    .then(function () {\n      return new Promise(function (resolve) {\n        requestAnimationFrame(function () {\n          requestAnimationFrame(resolve);\n        });\n      });\n    })\n    .then(function () {\n      return renderCanvas(page1);\n    })\n    .then(function (canvas1) {\n      var pdf = new JsPdfCtor({ orientation: \"p\", unit: \"mm\", format: \"a4\" });\n      addCanvasAsPage(pdf, canvas1, false);\n\n      if (!hasSolar) return pdf;\n\n      var page2 = makePage();\nhost.appendChild(page2);\nvar root2 = cloneInto(page2);\n\nsetPdfNotesVisible(root2, true);\n\napplyPdfVisibilityFromUi(root2);\npopulatePdfValuesFromUi(root2);\nupdatePdfCardDividers(root2);\n\nshowOnly(root2, [\"pdfSectionSolarTech\"]);\n\n      return forceAllImages(root2)\n        .then(function () {\n          return new Promise(function (resolve) {\n            requestAnimationFrame(function () {\n              requestAnimationFrame(resolve);\n            });\n          });\n        })\n        .then(function () {\n          return renderCanvas(page2);\n        })\n        .then(function (canvas2) {\n          addCanvasAsPage(pdf, canvas2, true);\n          return pdf;\n        });\n    })\n    .then(function (pdf) {\n      var projectInput = document.getElementById(\"tsProjectName\");\nvar projectName = projectInput && projectInput.value\n  ? String(projectInput.value).trim()\n  : \"\";\n\nvar filename = buildPdfFilename(\"SystemCalculator\", projectName);\npdf.save(filename);\n      cleanupHost();\n    })\n    .catch(function (err) {\n      cleanupHost();\n      throw err;\n    });\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nwindow.bindPdfButton = bindPdfButton;\nwindow.createSystemPdf = createSystemPdf;\n\n\n\n\/* =========================================================\n   Boot: robust for Elementor\n========================================================= *\/\n\n(function () {\n  function bootSystem() {\n    if (typeof window.initSystemCalculator !== \"function\") return;\n    if (window.__sysconfInitialized) return;\n    if (!document.getElementById(\"sysconfCalculatorForm\")) return;\n\n    window.__sysconfInitialized = true;\n    window.initSystemCalculator();\n\n    if (typeof window.bindPdfButton === \"function\") {\n      window.bindPdfButton();\n    }\n  }\n\n  if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", bootSystem);\n  else bootSystem();\n\n \n  (function keepPdfBound() {\n    var tries = 0;\n    var maxTries = 80;\n    var timer = window.setInterval(function () {\n      tries += 1;\n\n      if (typeof window.bindPdfButton === \"function\") {\n        window.bindPdfButton();\n      }\n\n      var btn = document.getElementById(\"tsCreatePdfBtn\");\n      if ((btn && btn.__tsPdfBound) || tries >= maxTries) {\n        window.clearInterval(timer);\n      }\n    }, 250);\n  })();\n\n  var tries = 0;\n  var maxTries = 80;\n  var timer = window.setInterval(function () {\n    tries += 1;\n    bootSystem();\n    if (window.__sysconfInitialized || tries >= maxTries) window.clearInterval(timer);\n  }, 100);\n})();\n\n\n\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4c49082 elementor-widget elementor-widget-html\" data-id=\"4c49082\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- =========================\nVIEW: PV (SSO calculator)\n========================= -->\n<div data-ts-mount=\"content\">\n  <section id=\"hiddenRootsPv\" style=\"display:none;\">\n\n    <div id=\"ssoCalculatorRoot\">\n\n      <section class=\"sso-calculator\">\n        <div class=\"sso-layout\">\n\n          <form id=\"ssoCalculatorForm\" class=\"sso-form\">\n<hr class=\"ps-summary-divider\">\n    <br>\n            <div class=\"sso-field-group\">\n              <div class=\"sso-label\"><strong>Panel configuration<\/strong><\/div>\n              <br>\n\n              <div style=\"display:flex;gap:12px;flex-wrap:wrap;\">\n                <div style=\"flex:1;min-width:140px;\">\n                  <label class=\"sso-label\" for=\"ssoNumPanels\">Number of panels<\/label>\n                  <input id=\"ssoNumPanels\" class=\"sso-input\" type=\"number\" min=\"1\" value=\"\" placeholder=\"Enter number\u2026\">\n                <\/div>\n\n                <div style=\"flex:1;min-width:140px;\">\n                  <label class=\"sso-label\" for=\"ssoMountType\">Mounting<\/label>\n                  <select id=\"ssoMountType\" class=\"sso-input\">\n                    <option value=\"tak\">Roof mounting<\/option>\n                    <option value=\"mark\">Ground mounting<\/option>\n                    <option value=\"fasad\">Fa\u00e7ade mounting<\/option>\n                  <\/select>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <br>\n\n            <div class=\"sso-field-group\">\n              <label class=\"sso-label\" for=\"ssoPanelSelect\">Model<\/label>\n              <select id=\"ssoPanelSelect\" class=\"sso-input\">\n                <option value=\"\">Select model<\/option>\n                <option value=\"manual\">Other model, enter values manually<\/option>\n              <\/select>\n            <\/div>\n\n            <div id=\"ssoManualModelGroup\" class=\"sso-field-group\" style=\"display:none;\">\n              <br>\n              <label class=\"sso-label\" for=\"ssoManualModel\">Panel model name (optional)<\/label>\n              <input id=\"ssoManualModel\" class=\"sso-input\" type=\"text\" placeholder=\"Enter panel model name\u2026\">\n            <\/div>\n\n       \n\n            <div id=\"ssoPanelDataToggleRow\" class=\"sso-toggle-row\" style=\"display:none;\" role=\"button\" tabindex=\"0\" aria-expanded=\"false\">\n              <span id=\"ssoPanelDataToggleText\" class=\"sso-toggle-text\">Show panel data<\/span>\n              <span id=\"ssoPanelDataToggleArrow\" class=\"sso-toggle-arrow\">\u25bc<\/span>\n            <\/div>\n\n            <div id=\"ssoPanelDataGroup\" style=\"display:none;margin-top:12px;\">\n              <div class=\"sso-label\">Panel data<\/div>\n              <br>\n\n              <div class=\"sso-panel-data-grid\" style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:12px 16px;\">\n                <div>\n                  <label for=\"ssoPanelPmax\">Pmax (W)<\/label>\n                  <input id=\"ssoPanelPmax\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n\n                <div>\n                  <label for=\"ssoPanelVmp\">Vmp (V)<\/label>\n                  <input id=\"ssoPanelVmp\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n\n                <div>\n                  <label for=\"ssoPanelVoc\">Voc (V)<\/label>\n                  <input id=\"ssoPanelVoc\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n\n                <div>\n                  <label for=\"ssoPanelImp\">Imp (A)<\/label>\n                  <input id=\"ssoPanelImp\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n\n                <div>\n                  <label for=\"ssoPanelIsc\">Isc (A)<\/label>\n                  <input id=\"ssoPanelIsc\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n\n                <div>\n                  <label for=\"ssoPanelVocCoeff\">Temp coeff Voc (%\/\u00b0C)<\/label>\n                  <input id=\"ssoPanelVocCoeff\" class=\"sso-input\" type=\"text\" readonly>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <br>\n\n            <input id=\"ssoMinTemperature\" type=\"hidden\" value=\"-20\">\n            <input id=\"ssoMaxTemperature\" type=\"hidden\" value=\"30\">\n\n          <\/form>\n\n          <div class=\"sso-field-group\" style=\"margin-top:12px;\">\n            <button type=\"button\" id=\"ssoCalcButton\" class=\"cc-submit\">\n              Run calculation\n            <\/button>\n          <\/div>\n\n          <div id=\"ssoAfterCalc\" style=\"display:none;\">\n            <br>\n            <hr class=\"ps-summary-divider\">\n\n            <aside id=\"ssoCalculatorResult\" class=\"sso-result\">\n              <h6>Calculation result<\/h6>\n\n              <div id=\"ssoResultDetails\" class=\"sso-result-details\" style=\"display:none;\">\n\n                <!-- Base results as text rows -->\n                <div class=\"sso-result-lines\">\n                  <div class=\"sso-result-line\">\n                    <div class=\"sso-result-label\">Total panel power<\/div>\n                    <div class=\"sso-result-value\" id=\"ssoResInstalledPower\"><\/div>\n                  <\/div>\n\n                  <div class=\"sso-result-line\">\n                    <div class=\"sso-result-label\">Number of SSO 8 kW<\/div>\n                    <div class=\"sso-result-value\" id=\"ssoResNumSso\"><\/div>\n                  <\/div>\n\n                  <div class=\"sso-result-line\">\n  <div class=\"sso-result-label\">Min\/max number of panels per SSO<\/div>\n  <div class=\"sso-result-value\" id=\"ssoResMinMaxPanelsPerSso\"><\/div>\n<\/div>\n\n<div id=\"ssoDistributionLines\"><\/div>\n                <\/div>\n               \n <div class=\"sso-field-group\" style=\"margin-top:14px;margin-bottom:4px;\">\n  <div class=\"ts-toggle-block\" id=\"ssoManualSsoToggleBlock\" style=\"margin-top:14px;margin-bottom:4px;\">\n    <div class=\"ts-toggle-head\">\n      <div class=\"ts-toggle-label\"><span class=\"sso-normal\">Enter SSO quantity manually<\/span><\/div>\n\n      <label class=\"ts-switch\">\n        <input type=\"checkbox\" id=\"ssoManualSsoToggle\">\n        <span class=\"ts-slider\" aria-hidden=\"true\"><\/span>\n      <\/label>\n    <\/div>\n\n    <div id=\"ssoManualSsoWrapper\" style=\"display:none;margin-top:10px;\">\n      <label for=\"ssoManualNumSso\" class=\"sso-label\" style=\"font-size:14px;\">\n        Manual SSO quantity\n      <\/label>\n      <input id=\"ssoManualNumSso\" class=\"sso-input\" type=\"number\" min=\"1\" step=\"1\" style=\"max-width:140px;\">\n    <\/div>\n  <\/div>\n<\/div>\n                <!-- Advanced details behind toggle -->\n                <div id=\"ssoAdvancedToggleRow\" class=\"sso-toggle-row\" style=\"display:none;margin-top:4px;\" role=\"button\" tabindex=\"0\" aria-expanded=\"false\">\n                  <span id=\"ssoAdvancedToggleText\" class=\"sso-toggle-text\">Show technical details<\/span>\n                  <span id=\"ssoAdvancedToggleArrow\" class=\"sso-toggle-arrow\">\u25bc<\/span>\n                <\/div>\n\n                <div id=\"ssoAdvancedGroup\" style=\"display:none;margin-top:10px;\">\n\n                  \n\n                  <div class=\"sso-result-lines\">\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Vmp nominal<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResVmpNominal\"><\/div>\n                    <\/div>\n\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Vmp min<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResVmpMin\"><\/div>\n                    <\/div>\n\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Vmp max<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResVmpMax\"><\/div>\n                    <\/div>\n\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Voc max<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResVocMax\"><\/div>\n                    <\/div>\n\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Imp max<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResImp\"><\/div>\n                    <\/div>\n\n                    <div class=\"sso-result-line\">\n                      <div class=\"sso-result-label\">Isc max<\/div>\n                      <div class=\"sso-result-value\" id=\"ssoResIsc\"><\/div>\n                    <\/div>\n                  <\/div>\n\n                <\/div>\n<div style=\"margin-top:10px;\">\n  <div id=\"ssoResDimension\" class=\"sso-dimension-status\" aria-live=\"polite\"><\/div>\n<\/div>\n               \n                <p id=\"ssoDimensionNote\" class=\"faCC-noteBox\" style=\"margin-top:18px;display:none;\"><\/p>\n\n\n\n\n              <\/div>\n            <\/aside>\n            <br>\n            <hr class=\"ps-summary-divider\">\n            <div class=\"sso-field-group\">\n              <h6>Documentation<\/h6>\n              <label for=\"ssoProjectName\">Project name (optional)<\/label>\n              <input id=\"ssoProjectName\" class=\"sso-input\" type=\"text\" placeholder=\"Enter project name\u2026\">\n            <\/div>\n\n            <br>\n<div class=\"sso-actions\">\n  <button type=\"button\" id=\"ssoExportButton\" class=\"cc-submit\">\n    Create PDF\n  <\/button>\n<\/div>\n            \n            <br>\n            <br>\n         <hr class=\"ps-summary-divider\">\n<div class=\"sso-notes\">\n  <div class=\"sso-notes-title\">Please note<\/div>\n  <ul class=\"sso-notes-list\">\n<li>The calculation is indicative and does not replace full system design.<\/li>\n    <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\n    <li>Panel calculations are based on the specified panel data. Bifacial gain is not included.<\/li>\n    <li>Reverse polarity protection is inactive for panels with Isc above 13.5 A.<\/li>\n    <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\n  <\/ul>\n<\/div>\n          <\/div>\n\n        <\/div>\n      <\/section>\n\n<!-- =========================\nSSO PDF TEMPLATE (matches System PDF page 2)\n========================= -->\n<section id=\"ssoPdfTemplate\" class=\"ts-hidden\" aria-hidden=\"true\">\n  <div class=\"tsPdfPage\" id=\"tsPdfPageSso\">\n\n    <div class=\"tsPdfHeader\">\n      <div class=\"tsPdfHeaderLeft\">\n        <div class=\"tsPdfTitle\">SSO documentation<\/div>\n        <div class=\"tsPdfMeta\">\n          <div class=\"tsPdfMetaRow\">\n            <div class=\"tsPdfMetaLabel\">Project name<\/div>\n            <div class=\"tsPdfMetaValue\" id=\"ssoPdfProjectName\">-<\/div>\n          <\/div>\n          <div class=\"tsPdfMetaRow\">\n            <div class=\"tsPdfMetaLabel\">Date<\/div>\n            <div class=\"tsPdfMetaValue\" id=\"ssoPdfDate\">-<\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"tsPdfBrand\">\n        <img decoding=\"async\"\n  id=\"ssoPdfBrandLogo\"\n  data-logo-url=\"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png.webp\"\n  src=\"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png.webp\"\n  alt=\"Ferroamp\"\n  crossorigin=\"anonymous\"\n  style=\"height:28px; width:auto; display:block;\"\n>\n      <\/div>\n    <\/div>\n\n    <div class=\"tsPdfSection\" id=\"ssoPdfSectionSolarTech\">\n      <div class=\"tsPdfSectionTitle\">SSO calculation<\/div>\n\n      <!-- Row 1 -->\n      <div class=\"tsPdfGrid2Cards\">\n        <div class=\"tsPdfCard\" id=\"ssoPdfPanelInputCard\">\n          <div class=\"tsPdfSubTitle\">Panel configuration<\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Panel model<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfPanelModel\">-<\/div>\n          <\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Quantity<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelCount\">-<\/span> pcs<\/div>\n          <\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Mounting<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfMountType\">-<\/div>\n          <\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Temperature<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfMinTemp\">-<\/span> to <span id=\"ssoPdfMaxTemp\">-<\/span> \u00b0C<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"tsPdfCard\" id=\"ssoPdfPanelDataCard\">\n          <div class=\"tsPdfSubTitle\">Panel data<\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Pmax<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelPmax\">-<\/span> W<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Vmp<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelVmp\">-<\/span> V<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Voc<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelVoc\">-<\/span> V<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Imp<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelImp\">-<\/span> A<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Isc<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelIsc\">-<\/span> A<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Voc coeff<\/div>\n            <div class=\"tsPdfValue\"><span id=\"ssoPdfPanelVocCoeff\">-<\/span> %<\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <!-- Row 2 -->\n      <div class=\"tsPdfGrid2Cards\" style=\"margin-top:24px;\">\n\n        <div class=\"tsPdfCard\" id=\"ssoPdfSolarBlock\">\n          <div class=\"tsPdfSubTitle\">Proposed string layout<\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Total panel power<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfSolarInstalled\">-<\/div>\n          <\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Number of SSO<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfNumSso\">-<\/div>\n          <\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Min\/max number of panels per SSO<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfMinMaxPanelsPerSso\">-<\/div>\n          <\/div>\n\n          <!-- Dynamic rows (created by JS as .tsPdfLine) -->\n          <div id=\"ssoPdfDistributionLines\" class=\"tsPdfDistribution\"><\/div>\n        <\/div>\n\n        <div class=\"tsPdfCard\" id=\"ssoPdfTechBlock\">\n          <div class=\"tsPdfSubTitle\">Technical string details<\/div>\n\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Vmp nominal<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfVmpNominal\">-<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Vmp min<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfVmpMin\">-<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Vmp max<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfVmpMax\">-<\/div>\n          <\/div>\n          <div class=\"tsPdfLine\">\n            <div class=\"tsPdfLabel\">Voc max<\/div>\n            <div class=\"tsPdfValue\" id=\"ssoPdfVocMax\">-<\/div>\n          <\/div>\n        <\/div>\n\n      <\/div>\n    <\/div>\n\n\n\n<!-- =========================\nPDF NOTE: Important assumptions and limitations\nSSO\n========================= -->\n<div class=\"tsPdfSection\" id=\"ssoPdfSectionNotes\">\n  <div class=\"tsPdfNoteBox\" id=\"ssoPdfNoteBox\">\n  <div class=\"tsPdfNoteTitle\">Please note<\/div>\n  <ul class=\"tsPdfNoteList\" id=\"ssoPdfNoteList\">\n<li>The calculation is indicative and does not replace full system design.<\/li>\n    <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\n    <li>Panel calculations are based on the specified panel data. Bifacial gain is not included.<\/li>\n    <li>Reverse polarity protection is inactive for panels with Isc above 13.5 A.<\/li>\n    <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\n  <\/ul>\n<\/div>\n\n\n\n<\/div>\n  <\/div>\n<\/section>\n\n<!-- Host for render (same principle as system) -->\n<div id=\"ssoPdfHost\"\n     style=\"position:fixed; left:-10000px; top:0; width:794px; background:#fff; pointer-events:none; z-index:2147483647; opacity:1;\"><\/div>\n\n \n\n    \n\n      <style>\n      \n      \n      :root{\n  --tsPdfW: 794px;\n  --tsPdfPadX: 56px;\n  --tsPdfPadY: 48px;\n  --ts-text:#111;\n  --ts-muted:#666;\n}\n\n\n        .sso-print-sheet {\n          display:none;\n          position:fixed;\n          left:0;\n          top:0;\n          width:210mm;\n          padding:24px;\n          background:#fff;\n          font-family:system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;\n        }\n        .sso-print-header h1 { margin:0 0 8px; }\n        .sso-print-section { margin-top:16px; }\n        .sso-print-table {\n          width:100%;\n          border-collapse:collapse;\n          margin-bottom:8px;\n          font-size:13px;\n        }\n        .sso-print-table th,\n        .sso-print-table td {\n          border-bottom:1px solid #ccc;\n          padding:4px 6px;\n          text-align:left;\n        }\n        .sso-print-table th { width:45%; font-weight:600; }\n        .sso-print-note { margin-top:12px; }\n        .sso-print-footer-note { margin-top:8px; font-size:11px; color:#555; }\n        input[type=number]::-webkit-inner-spin-button,\n        input[type=number]::-webkit-outer-spin-button { -webkit-appearance:none; margin:0; }\n        input[type=number] { -moz-appearance:textfield; }\n\n        .sso-toggle-row {\n          user-select:none;\n          cursor:pointer;\n          display:inline-flex;\n          align-items:center;\n          gap:6px;\n          padding:6px 0;\n        }\n        .sso-toggle-row:hover .sso-toggle-text { text-decoration:underline; }\n        .sso-toggle-arrow {\n          display:inline-block;\n          transition:transform 0.2s;\n        }\n\n        .sso-result-lines {\n          width:100%;\n          border:1px solid #e6e6e6;\n          border-radius:8px;\n          padding:10px 12px;\n          background:#fff;\n        }\n        .sso-result-line {\n          display:flex;\n          align-items:flex-start;\n          justify-content:space-between;\n          gap:12px;\n          padding:8px 0;\n          border-bottom:1px solid #f0f0f0;\n        }\n        .sso-result-line:last-child { border-bottom:none; }\n        .sso-result-label {\n          color:#222;\n        }\n        .sso-result-value {\n          text-align:right;\n          min-width:110px;\n          color:#222;\n          white-space:nowrap;\n        }\n        \n        \n        .sso-dimension-status{\n  display:inline-flex;\n  align-items:center;\n  justify-content:center;\n  gap:10px;\n\n  width:auto;\n  max-width:100%;\n\n  padding:10px 14px;\n  border-radius:10px;\n\n  font-weight:700;\n  line-height:1.2;\n\n  border:1px solid rgba(0,0,0,.10);\n  background:#fff;\n}\n\n.sso-dimension-status .sso-dimension-icon{\n  width:18px;\n  height:18px;\n  display:inline-block;\n}\n\n.sso-dimension-status.is-ok{\n  border-color:rgba(127, 181, 47, .35);\n  background:rgba(157, 200, 71, .20);\n  color:#111;\n}\n\n.sso-dimension-status.is-bad{\n  border-color:rgba(192, 0, 0, .35);\n  background:rgba(192, 0, 0, .12);\n  color:#111;\n}\n\n        \n        \n        \n        \n        \n        \/* System: force same button look as SSO *\/\n#sysconfCalcBtn.cc-submit{\n  background:#9dc847 !important;\n  color:#000 !important;\n  font-weight:600 !important;\n\n  width:auto !important;\n  display:inline-flex !important;\n  align-items:center !important;\n  justify-content:center !important;\n\n  border:0 !important;\n  border-radius:10px !important;\n  padding:12px 22px !important;\n\n  line-height:1.1 !important;\n  text-decoration:none !important;\n  text-transform:none !important;\n\n  box-shadow:none !important;\n}\n\n\n\n\n\n\/* Cable calculator info *\/\n#faCableCalcRoot #ssoDimensionNote.faCC-noteBox{\n  background:#fff !important;\n  border:2px solid rgba(0,0,0,.12) !important;\n  border-radius:12px !important;\n  padding:10px 12px !important;\n  color: var(--faCC-text, #111) !important;\n  font-size:14px !important;\n  line-height:1.35 !important;\n}\n\n\/* OK *\/\n#faCableCalcRoot #ssoDimensionNote.faCC-noteBox.is-ok{\n  border-color: var(--faCC-green, #7fb52f) !important;\n}\n\n\/* Not OK *\/\n#faCableCalcRoot #ssoDimensionNote.faCC-noteBox.is-bad{\n  border-color:#d92d20 !important;\n}\n\n\n\n\n\/* Hover\/focus to match SSO feel *\/\n#sysconfCalcBtn.cc-submit:hover{\n  filter:brightness(0.98);\n}\n\n#sysconfCalcBtn.cc-submit:focus{\n  outline:0 !important;\n}\n\n#sysconfCalcBtn.cc-submit:focus-visible{\n  outline:2px solid rgba(127, 181, 47, 0.35) !important;\n  outline-offset:2px !important;\n}\n\n#ssoCalculatorRoot #ssoExportButton.cc-submit{\n  width:auto !important;\n  display:inline-flex !important;\n  padding:12px 22px !important;\n  align-self:flex-start;\n}\n\n\n\n\n\n\n\n\n.sso-dimension-status{\n  display:block;\n  width:100%;\n}\n\n.sso-dimension-title-row{\n  display:flex;\n  align-items:center;\n  justify-content:space-between;\n  gap:10px;\n}\n\n.sso-dimension-title-text{\n  font-weight:700;\n  line-height:1.2;\n}\n\n.sso-dimension-body{\n  margin-top:8px;\n  font-weight:400;\n  line-height:1.35;\n}\n\n\n\n\n\/* Hide template on page but keep renderable via host *\/\n#ssoPdfTemplate{\n  position:fixed !important;\n  left:-10000px !important;\n  top:0 !important;\n  width:var(--tsPdfW) !important;\n  max-width:var(--tsPdfW) !important;\n  visibility:hidden !important;\n  pointer-events:none !important;\n}\n#ssoCalculatorRoot #ssoPdfTemplate{ display:none !important; }\n\n\/* Host render *\/\n#ssoPdfHost{\n  width:var(--tsPdfW) !important;\n  max-width:var(--tsPdfW) !important;\n  overflow:hidden !important;\n  background:#fff !important;\n}\n#ssoPdfHost #ssoPdfTemplate{\n  display:block !important;\n  position:static !important;\n  left:auto !important;\n  top:auto !important;\n  width:var(--tsPdfW) !important;\n  max-width:var(--tsPdfW) !important;\n  visibility:visible !important;\n  pointer-events:none !important;\n}\n\n\/* Page *\/\n#ssoPdfHost .tsPdfPage{\n  width:var(--tsPdfW) !important;\n  max-width:var(--tsPdfW) !important;\n  box-sizing:border-box !important;\n  padding:var(--tsPdfPadY) var(--tsPdfPadX) !important;\n  background:#fff !important;\n  font-family:system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif !important;\n  color:var(--ts-text, #111) !important;\n  overflow:hidden !important;\n}\n\n\/* Header *\/\n#ssoPdfHost .tsPdfHeader{\n  display:flex;\n  justify-content:space-between;\n  align-items:flex-start;\n  gap:24px;\n  margin-bottom:22px;\n}\n#ssoPdfHost .tsPdfTitle{\n  font-size:26px;\n  font-weight:700;\n  line-height:1.15;\n}\n#ssoPdfHost .tsPdfMeta{ margin-top:10px; }\n#ssoPdfHost .tsPdfMetaRow{\n  display:flex;\n  justify-content:space-between;\n  gap:12px;\n  font-size:12px;\n  color:var(--ts-muted, #666);\n  padding:3px 0;\n}\n#ssoPdfHost .tsPdfMetaValue{\n  font-weight:600;\n  color:var(--ts-text, #111);\n  white-space:nowrap;\n}\n\n\/* Sections *\/\n#ssoPdfHost .tsPdfSection{ margin-top:16px; }\n#ssoPdfHost .tsPdfSectionTitle{\n  font-size:14px;\n  font-weight:700;\n  margin:0 0 10px 0;\n}\n\n\/* 2-card grid *\/\n#ssoPdfHost .tsPdfGrid2Cards{\n  display:grid;\n  grid-template-columns: 1fr 1fr;\n  column-gap:16px;\n  row-gap:22px;\n  width:100% !important;\n  max-width:100% !important;\n}\n\n\/* Cards *\/\n#ssoPdfHost .tsPdfCard{\n  border:1px solid #ededed;\n  border-radius:14px;\n  padding:12px 14px;\n  background:#fff;\n  min-width:0 !important;\n}\n#ssoPdfHost .tsPdfSubTitle{\n  margin:12px 0 6px 0;\n  font-size:13px;\n  font-weight:700;\n  color:var(--ts-text, #111);\n}\n\n\/* Lines *\/\n#ssoPdfHost .tsPdfLine{\n  display:flex;\n  justify-content:space-between;\n  gap:16px;\n  padding:7px 0;\n  border-bottom:1px solid #ededed;\n  box-sizing:border-box;\n}\n#ssoPdfHost .tsPdfLine:last-child{ border-bottom:0; }\n#ssoPdfHost .tsPdfLabel{\n  font-size:12.5px;\n  font-weight:400;\n  color:var(--ts-text, #111);\n  min-width:0;\n}\n#ssoPdfHost .tsPdfValue{\n  font-size:12.5px;\n  font-weight:600;\n  color:var(--ts-text, #111);\n  text-align:right;\n  min-width:0 !important;\n  overflow-wrap:anywhere;\n  white-space:nowrap;\n}\n\n\/* Distribution lines *\/\n#ssoPdfHost .tsPdfDistribution{ margin-top:10px; }\n#ssoPdfHost .tsPdfDistribution .tsPdfLine{ padding:6px 0; }\n\n\n#ssoPdfTemplate #ssoPdfBrandLogo{\n  visibility: visible !important;\n}\n\n#ssoCalculatorRoot #ssoPdfTemplate{ display:none !important; }\n\n\n#ssoPdfHost #ssoPdfTemplateRender{\n  display:block !important;\n  visibility:visible !important;\n}\n\n\n\/* =========================\n   Cable: tighter spacing between heading and fields\n   Scope: cable calculator only\n========================= *\/\n#kabelkalkylatorPrint .sso-field-group{\n  margin:0 0 14px 0 !important;\n}\n\n#kabelkalkylatorPrint .sso-field-group > label.sso-label,\n#kabelkalkylatorPrint label.sso-label{\n  margin:0 0 6px 0 !important;\n  padding:0 !important;\n  line-height:1.2 !important;\n}\n\n#kabelkalkylatorPrint .sso-unit{\n  margin:0 !important;\n}\n#kabelkalkylatorPrint .sso-unit-text{\n  margin:0 !important;\n}\n\n#kabelkalkylatorPrint input.sso-input,\n#kabelkalkylatorPrint select.sso-input{\n  margin-top:0 !important;\n}\n\n#kabelkalkylatorPrint .sso-grid-3{\n  margin-top:0 !important;\n}\n\n.sso-notes {\n  margin-top: 14px;\n  color: #8a8a8a;\n  font-size: 13px;\n  line-height: 1.45;\n}\n\n.sso-notes-title {\n  font-weight: 600;\n  color: #7a7a7a;\n  margin-bottom: 6px;\n}\n\n.sso-notes-list {\n  margin: 0;\n  padding-left: 16px;\n}\n\n.sso-notes-list li {\n  margin: 2px 0;\n}\n\n\n\n\/* PDF: allow wrapping for long panel names (panel model only) *\/\n#ssoPdfHost #ssoPdfPanelModel,\n#ssoPdfTemplate #ssoPdfPanelModel{\n  white-space: normal !important;\n  overflow-wrap: anywhere !important;\n  word-break: break-word !important;\n  text-align: right;\n  max-width: 100%;\n}\n\n\n\n\n\/* =========================================================\n   SSO PDF: note block (important assumptions and limitations)\n   Scope: notes section only\n========================================================= *\/\n#ssoPdfHost #ssoPdfSectionNotes .tsPdfNoteBox,\n#ssoPdfTemplate #ssoPdfSectionNotes .tsPdfNoteBox{\n  margin-top: 36px;\n  padding: 0;\n  background: transparent;\n  color: rgba(0,0,0,0.55);\n  font-size: 11.5px;\n  line-height: 1.35;\n}\n\n#ssoPdfHost #ssoPdfSectionNotes .tsPdfNoteTitle,\n#ssoPdfTemplate #ssoPdfSectionNotes .tsPdfNoteTitle{\n  font-weight: 600;\n  color: rgba(0,0,0,0.70);\n  font-size: 12px;\n  margin: 0 0 4px 0;\n}\n\n#ssoPdfHost #ssoPdfSectionNotes .tsPdfNoteList,\n#ssoPdfTemplate #ssoPdfSectionNotes .tsPdfNoteList{\n  margin: 0;\n  padding-left: 14px;\n}\n\n#ssoPdfHost #ssoPdfSectionNotes .tsPdfNoteList li,\n#ssoPdfTemplate #ssoPdfSectionNotes .tsPdfNoteList li{\n  margin: 1px 0;\n}\n\n\n\n\n#toolSuiteChooser #viewPv .ts-toggle-head{\n  display:flex;\n  align-items:center;\n  gap:12px;\n}\n#toolSuiteChooser #viewPv .ts-toggle-label{\n  font-weight:700;\n  line-height:1.2;\n}\n#toolSuiteChooser #viewPv .ts-switch{\n  position:relative;\n  width:38px;\n  height:20px;\n  flex:0 0 auto;\n}\n#toolSuiteChooser #viewPv .ts-switch input{\n  position:absolute;\n  inset:0;\n  width:100%;\n  height:100%;\n  opacity:0;\n  margin:0;\n  cursor:pointer;\n}\n#toolSuiteChooser #viewPv .ts-slider{\n  position:absolute;\n  inset:0;\n  background:#d9d9d9;\n  transition:0.18s;\n  border-radius:999px;\n  pointer-events:none;\n}\n#toolSuiteChooser #viewPv .ts-slider:before{\n  content:\"\";\n  position:absolute;\n  height:14px;\n  width:14px;\n  left:3px;\n  top:3px;\n  background:#fff;\n  transition:0.18s;\n  border-radius:50%;\n  box-shadow:0 1px 2px rgba(0,0,0,0.20);\n}\n#toolSuiteChooser #viewPv .ts-switch input:checked + .ts-slider{\n  background:var(--fa-green, #7fb52f);\n}\n#toolSuiteChooser #viewPv .ts-switch input:checked + .ts-slider:before{\n  transform:translateX(18px);\n}\n\n\n\n\n\n#toolSuiteChooser #viewPv #ssoManualSsoToggleBlock .sso-normal{\n  font-weight:400 !important;\n}\n\n\n\n\n\n\n\n\n\n\n@media (max-width: 767px){\n\n  \/* SSO: allow \"Enter SSO quantity manually\" to wrap on mobile *\/\n  #toolSuiteChooser #viewPv label.sso-help{\n    white-space: normal !important;\n    flex-wrap: wrap !important;\n    max-width: 100% !important;\n    overflow-wrap: anywhere !important;\n    word-break: break-word !important;\n  }\n\n  #toolSuiteChooser #viewPv #ssoManualSsoToggle{\n    flex: 0 0 auto !important;\n  }\n\n  #toolSuiteChooser #viewPv .sso-result-lines{\n    overflow-x: hidden !important;\n  }\n  \n    #toolSuiteChooser #viewPv #ssoAfterCalc .sso-actions{\n    display:flex !important;\n    justify-content:flex-start !important;\n    align-items:flex-start !important;\n  }\n\n  #toolSuiteChooser #viewPv #ssoAfterCalc .sso-actions > #ssoExportButton{\n    width:auto !important;\n    max-width:none !important;\n    display:inline-flex !important;\n    flex:0 0 auto !important;\n  }\n}\n\n\n#toolSuiteChooser input.sso-input,\n#toolSuiteChooser select.sso-input {\n  border: 1px solid #e6e6e6 !important;\n  background: #f7f8f8 !important;\n  box-shadow: none !important;\n  border-radius: 6px;\n}\n\n#toolSuiteChooser input.sso-input,\n#toolSuiteChooser select.sso-input {\n  box-sizing: border-box;\n  width: 100%;\n\n  font-size: 16px !important;      \/* tvinga textstorlek *\/\n  line-height: 22px !important;    \/* tvinga radavst\u00e5nd *\/\n\n  padding: 10px 14px;\n\n  border-radius: 4px;\n  border-width: 1px;\n  border-style: solid;\n  border-color: #e6e6e6 !important;\n  background-color: #f7f8f8 !important;\n\n  box-shadow: none !important;\n  outline: none;\n}\n\n\/* Avst\u00e5nd mellan rubriktext (label) och f\u00e4lt *\/\n#toolSuiteChooser .sso-label {\n  margin-bottom: 10px !important;\n}\n\n\n      <\/style>\n\n    <\/div>\n\n  <\/section>\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7716df6 elementor-widget elementor-widget-html\" data-id=\"7716df6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n\n<script>\n\/* PV init wrapper *\/\nwindow.initSsoCalculator = function initSsoCalculator() {\n  \"use strict\";\n\n  if (window.__ssoInitialized) return;\n  if (!document.getElementById(\"ssoCalculatorForm\")) return;\n\n  window.__ssoInitialized = true;\n\n  (function () {\n    \/\/ ------------------------------------\n    \/\/ Helpers\n    \/\/ ------------------------------------\n    function byId(id) { return document.getElementById(id); }\n\n    function toNumber(value) {\n      if (value === null || value === undefined) return NaN;\n      var str = String(value).trim().replace(',', '.');\n      if (!str) return NaN;\n      var n = parseFloat(str);\n      return isNaN(n) ? NaN : n;\n    }\n\n    function formatNumber(value, decimals) {\n      var n = toNumber(value);\n      if (!isFinite(n)) return '-';\n      var d = typeof decimals === 'number' ? decimals : 2;\n      return n.toLocaleString('sv-SE', {\n        minimumFractionDigits: d,\n        maximumFractionDigits: d\n      });\n    }\n    \n    function sanitizeFileNamePart(value) {\n  var s = String(value || \"\").trim();\n  if (!s) return \"\";\n\n  \/\/ Svenska tecken och typiska specialtecken -> filv\u00e4nligt\n  s = s\n    .replace(\/\u00e5\/gi, \"a\")\n    .replace(\/\u00e4\/gi, \"a\")\n    .replace(\/\u00f6\/gi, \"o\")\n    .replace(\/[^a-z0-9]+\/gi, \"_\")   \/\/ allt annat -> _\n    .replace(\/^_+|_+$\/g, \"\")        \/\/ trim _\n    .replace(\/_+\/g, \"_\");           \/\/ collapse\n\n  return s;\n}\n\n    function scrollToElement(el) {\n      if (!el) return;\n      try {\n        el.scrollIntoView({ behavior: 'smooth', block: 'start' });\n      } catch (e) {\n        var y = el.getBoundingClientRect().top + window.pageYOffset;\n        window.scrollTo(0, y);\n      }\n    }\n    \n    function preloadImage(imgEl, timeoutMs) {\n  return new Promise(function (resolve) {\n    if (!imgEl) return resolve();\n\n    var done = false;\n    function finish() {\n      if (done) return;\n      done = true;\n      resolve();\n    }\n\n    \/\/ Redan laddad\n    if (imgEl.complete && imgEl.naturalWidth > 0) return resolve();\n\n    imgEl.addEventListener(\"load\", finish, { once: true });\n    imgEl.addEventListener(\"error\", finish, { once: true });\n\n    \/\/ decode n\u00e4r det finns st\u00f6d\n    if (imgEl.decode) {\n      imgEl.decode().then(finish).catch(function () { \/* fall back till events *\/ });\n    }\n\n    \/\/ Timeout, hellre PDF utan logga \u00e4n att fastna\n    setTimeout(finish, typeof timeoutMs === \"number\" ? timeoutMs : 3000);\n  });\n}\n\n\nfunction forcePdfLogo(pdfRoot) {\n  if (!pdfRoot) return Promise.resolve();\n\n  var img = pdfRoot.querySelector(\"#ssoPdfBrandLogo\");\n  if (!img) return Promise.resolve();\n\n  var logoUrl = (window.toolSuiteData && window.toolSuiteData.brandLogoUrl)\n    ? String(window.toolSuiteData.brandLogoUrl)\n    : (img.getAttribute(\"data-logo-url\") || img.getAttribute(\"src\") || \"\");\n\n  if (!logoUrl) return Promise.resolve();\n\n  \/\/ Rensa lazy-attribut\n  img.removeAttribute(\"data-src\");\n  img.removeAttribute(\"data-lazy-src\");\n  img.removeAttribute(\"data-srcset\");\n  img.removeAttribute(\"data-lazy-srcset\");\n  img.removeAttribute(\"data-original\");\n  img.removeAttribute(\"srcset\");\n\n  \/\/ S\u00e4kerst\u00e4ll synlighet\n  img.style.setProperty(\"display\", \"block\", \"important\");\n  img.style.setProperty(\"visibility\", \"visible\", \"important\");\n  img.style.setProperty(\"opacity\", \"1\", \"important\");\n\n  \/\/ Data\/blob ska inte f\u00e5 cache-buster\n  var isData = \/^data:\/i.test(logoUrl);\n  var isBlob = \/^blob:\/i.test(logoUrl);\n\n  \/\/ S\u00e4tt CORS endast n\u00e4r det \u00e4r en riktig URL\n  if (!isData && !isBlob) {\n    img.crossOrigin = \"anonymous\";\n    img.referrerPolicy = \"no-referrer\";\n\n    var bust = \"cb=\" + Date.now();\n    logoUrl = logoUrl + (logoUrl.indexOf(\"?\") >= 0 ? \"&\" : \"?\") + bust;\n  }\n\n  img.src = logoUrl;\n\n  return preloadImage(img, 3500);\n}\n\nfunction safeFileToken(str) {\n  if (str == null) return \"\";\n  var s = String(str).trim();\n\n  s = s\n    .replace(\/[\u00e5\u00c5]\/g, \"a\")\n    .replace(\/[\u00e4\u00c4]\/g, \"a\")\n    .replace(\/[\u00f6\u00d6]\/g, \"o\")\n    .replace(\/[^a-zA-Z0-9]+\/g, \"_\")\n    .replace(\/^_+|_+$\/g, \"\")\n    .replace(\/_+\/g, \"_\");\n\n  return s;\n}\n\nfunction todayYyyyMmDd() {\n  var dt = new Date();\n  return (\n    dt.getFullYear() +\n    String(dt.getMonth() + 1).padStart(2, \"0\") +\n    String(dt.getDate()).padStart(2, \"0\")\n  );\n}\n\nfunction buildPdfFilename(prefix, projectName) {\n  var dateToken = todayYyyyMmDd();\n  var proj = safeFileToken(projectName);\n\n  var base = prefix + \"_\" + dateToken;\n  if (proj) base += \"_\" + proj;\n\n  return base + \".pdf\";\n}\n\n\n\n\n\n\n\n    \/\/ ------------------------------------\n    \/\/ Dimension note: vit bakgrund, gr\u00f6n eller r\u00f6d kant\n    \/\/ ------------------------------------\n    function ensureDimensionNoteBaseStyle() {\n      var el = byId(\"ssoDimensionNote\");\n      if (!el) return;\n\n      \/\/ Tvinga vit bakgrund oavsett tidigare inline-styles\n      el.style.backgroundColor = \"#fff\";\n      el.style.color = \"#000\";\n      el.style.borderStyle = \"solid\";\n      el.style.borderWidth = \"2px\";\n      el.style.borderRadius = \"12px\";\n      el.style.padding = \"10px 12px\";\n\n      \/\/ Visa radbrytningar n\u00e4r vi anv\u00e4nder textContent\n      el.style.whiteSpace = \"pre-line\";\n\n      \/\/ Default border (neutral) n\u00e4r ingen status finns\n      if (!el.classList.contains(\"is-ok\") && !el.classList.contains(\"is-bad\")) {\n        el.style.borderColor = \"rgba(0,0,0,.15)\";\n      }\n    }\n\n    function setDimensionNote(text, status) {\n      var el = byId(\"ssoDimensionNote\");\n      if (!el) return;\n\n      ensureDimensionNoteBaseStyle();\n\n      el.classList.remove(\"is-ok\");\n      el.classList.remove(\"is-bad\");\n\n      if (status === \"ok\") el.classList.add(\"is-ok\");\n      if (status === \"bad\") el.classList.add(\"is-bad\");\n\n      \/\/ Border-f\u00e4rg styrs av status, bakgrund alltid vit\n      if (status === \"ok\") el.style.borderColor = \"#7fb52f\";\n      else if (status === \"bad\") el.style.borderColor = \"#c00000\";\n      else el.style.borderColor = \"rgba(0,0,0,.15)\";\n\n      el.textContent = text || \"\";\n      el.style.display = text ? \"block\" : \"none\";\n    }\n\n    function clearDimensionNote() {\n      var el = byId(\"ssoDimensionNote\");\n      if (!el) return;\n\n      ensureDimensionNoteBaseStyle();\n\n      el.classList.remove(\"is-ok\");\n      el.classList.remove(\"is-bad\");\n      el.style.borderColor = \"rgba(0,0,0,.15)\";\n      el.textContent = \"\";\n      el.style.display = \"none\";\n    }\n\n    function normalizeManualNumSsoInput() {\n      if (!manualNumSsoInput) return null;\n\n      var raw = String(manualNumSsoInput.value || '').trim();\n\n      \/\/ Till\u00e5t tomt f\u00e4lt\n      if (!raw) return null;\n\n      var n = toNumber(raw);\n      if (!isFinite(n) || n <= 0) {\n        manualNumSsoInput.value = '';\n        return null;\n      }\n\n      var ceiled = Math.ceil(n);\n\n      if (String(ceiled) !== raw) {\n        manualNumSsoInput.value = String(ceiled);\n      }\n\n      return ceiled;\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Integer distribution (no fractional panels)\n    \/\/ ------------------------------------\n    function getIntegerDistribution(totalPanels, numSso) {\n      var tp = toNumber(totalPanels);\n      var ns = toNumber(numSso);\n\n      if (!isFinite(tp) || !isFinite(ns) || ns <= 0) return null;\n\n      tp = Math.round(tp);\n      ns = Math.round(ns);\n\n      if (tp <= 0 || ns <= 0) return null;\n\n      var floorPanels = Math.floor(tp \/ ns);\n      var ceilPanels = Math.ceil(tp \/ ns);\n\n      var remainder = tp - (floorPanels * ns);\n\n      return {\n        floorPanels: floorPanels,\n        ceilPanels: ceilPanels,\n        numCeilStrings: remainder,\n        numFloorStrings: ns - remainder\n      };\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Fill panel dropdown\n    \/\/ ------------------------------------\nfunction fillSsoPanelSelect() {\n  var sel = byId('ssoPanelSelect');\n  if (!sel) return;\n\n  \/\/ H\u00e4mta paneldata fr\u00e5n ACF \/ global JS\n  var panels =\n    (window.toolSuiteData && Array.isArray(window.toolSuiteData.ssoPanels))\n      ? window.toolSuiteData.ssoPanels\n      : (Array.isArray(window.ssoPanels) ? window.ssoPanels : []);\n\n  \/\/ Om ingen data alls \u2013 l\u00e4mna befintligt som fallback\n  if (!panels || !panels.length) {\n    return;\n  }\n\n  \/\/ Plocka ev. befintliga texter fr\u00e5n HTML:n\n  var existingPlaceholder = sel.querySelector('option[value=\"\"]');\n  var existingManual      = sel.querySelector('option[value=\"manual\"]');\n\n  var placeholderText = existingPlaceholder\n    ? existingPlaceholder.textContent\n    : 'Select model';\n\n  var manualText = existingManual\n    ? existingManual.textContent\n    : 'Other model, enter values manually';\n\n  \/\/ Bygg listan p\u00e5 nytt: placeholder \u2192 Other \u2192 alla panelmodeller\n  sel.innerHTML = '';\n\n  \/\/ 1) Placeholder\n  var placeholderOpt = document.createElement('option');\n  placeholderOpt.value = '';\n  placeholderOpt.textContent = placeholderText;\n  sel.appendChild(placeholderOpt);\n\n  \/\/ 2) Other \/ manual-val\n  var manualOpt = document.createElement('option');\n  manualOpt.value = 'manual';\n  manualOpt.textContent = manualText;\n  sel.appendChild(manualOpt);\n\n  \/\/ 3) Panelmodeller fr\u00e5n ACF\n  panels.forEach(function (p, idx) {\n    if (!p) return;\n    var opt = document.createElement('option');\n    opt.value = String(p.id != null ? p.id : idx);\n    opt.textContent = p.modell || ('Panel ' + (idx + 1));\n    sel.appendChild(opt);\n  });\n}\n\n    fillSsoPanelSelect();\n\n    \/\/ ------------------------------------\n    \/\/ Paneldata toggle\n    \/\/ ------------------------------------\n    var panelDataGroup = byId('ssoPanelDataGroup');\n    var panelDataToggleRow = byId('ssoPanelDataToggleRow');\n    var panelDataToggleText = byId('ssoPanelDataToggleText');\n    var panelDataToggleArrow = byId('ssoPanelDataToggleArrow');\n\n    var isPanelDataOpen = false;\n\n    function setPanelDataOpen(open) {\n      isPanelDataOpen = !!open;\n\n      if (panelDataGroup) panelDataGroup.style.display = isPanelDataOpen ? '' : 'none';\n      if (panelDataToggleText) panelDataToggleText.textContent = isPanelDataOpen ? 'Hide panel data' : 'Show panel data';\n      if (panelDataToggleArrow) panelDataToggleArrow.style.transform = isPanelDataOpen ? 'rotate(180deg)' : 'rotate(0deg)';\n    }\n\n    function setPanelDataToggleAvailable(available) {\n      if (panelDataToggleRow) panelDataToggleRow.style.display = available ? '' : 'none';\n      if (!available) setPanelDataOpen(false);\n    }\n\n    if (panelDataToggleRow) {\n      panelDataToggleRow.addEventListener('click', function () {\n        setPanelDataOpen(!isPanelDataOpen);\n      });\n      panelDataToggleRow.addEventListener('keydown', function (e) {\n        if (e.key === 'Enter' || e.key === ' ') {\n          e.preventDefault();\n          setPanelDataOpen(!isPanelDataOpen);\n        }\n      });\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Advanced result toggle\n    \/\/ ------------------------------------\n    var advancedGroup = byId('ssoAdvancedGroup');\n    var advancedToggleRow = byId('ssoAdvancedToggleRow');\n    var advancedToggleText = byId('ssoAdvancedToggleText');\n    var advancedToggleArrow = byId('ssoAdvancedToggleArrow');\n\n    var isAdvancedOpen = false;\n\n    function setAdvancedOpen(open) {\n      isAdvancedOpen = !!open;\n      if (advancedGroup) advancedGroup.style.display = isAdvancedOpen ? '' : 'none';\n      if (advancedToggleText) advancedToggleText.textContent = isAdvancedOpen ? 'Hide technical details' : 'Show technical details';\n      if (advancedToggleArrow) advancedToggleArrow.style.transform = isAdvancedOpen ? 'rotate(180deg)' : 'rotate(0deg)';\n    }\n\n    function setAdvancedToggleAvailable(available) {\n      if (advancedToggleRow) advancedToggleRow.style.display = available ? '' : 'none';\n      if (!available) setAdvancedOpen(false);\n    }\n\n    if (advancedToggleRow) {\n      advancedToggleRow.addEventListener('click', function () {\n        setAdvancedOpen(!isAdvancedOpen);\n      });\n      advancedToggleRow.addEventListener('keydown', function (e) {\n        if (e.key === 'Enter' || e.key === ' ') {\n          e.preventDefault();\n          setAdvancedOpen(!isAdvancedOpen);\n        }\n      });\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Load panels and limits\n    \/\/ ------------------------------------\n    var panelsList = [];\n    if (window.toolSuiteData && Array.isArray(window.toolSuiteData.ssoPanels)) {\n      panelsList = window.toolSuiteData.ssoPanels;\n    } else if (Array.isArray(window.ssoPanels)) {\n      panelsList = window.ssoPanels;\n    }\n\n    var rawLimits = {};\n    if (window.toolSuiteData && window.toolSuiteData.ssoLimits) {\n      rawLimits = window.toolSuiteData.ssoLimits;\n    } else if (window.ssoLimits) {\n      rawLimits = window.ssoLimits;\n    }\n\n    function getLimit(key, fallback) {\n      if (!rawLimits) return fallback;\n\n      var k1 = String(key);\n      var k2 = String(key).toLowerCase();\n      var k3 = String(key).toUpperCase();\n\n      var v = (rawLimits[k1] !== undefined) ? rawLimits[k1]\n            : (rawLimits[k2] !== undefined) ? rawLimits[k2]\n            : (rawLimits[k3] !== undefined) ? rawLimits[k3]\n            : undefined;\n\n      var n = toNumber(v);\n      return isFinite(n) ? n : fallback;\n    }\n\n    var LIMIT_VOC_MAX_BASE        = getLimit('sso2_voc', 1000);\n    var LIMIT_VOC_MAX_REDUCED     = getLimit('sso2_voc2', 720);\n    var LIMIT_VMP_LOW             = getLimit('sso2_vmp_low', 100);\n    var LIMIT_VMP_HIGH_BASE       = getLimit('sso2_vmp_high', 720);\n\n    var LIMIT_ISC_REDUCED         = getLimit('sso2_isc_reduced', 13);\n\n    var LIMIT_IMP_NO_LIMIT        = getLimit('sso2_imp_reduced', 12.5);\n    var LIMIT_IMP_REDUCE_UNTIL    = getLimit('sso2_imp_reduced2', 14);\n    var LIMIT_IMP_MAX             = getLimit('sso2_imp_reduced3', 16);\n    var LIMIT_IMP_REDUCE_STEP_A   = 0.1; \/\/ A per steg\n    var LIMIT_IMP_REDUCE_STEP_V   = 8;   \/\/ V per steg (0,1 A)\n\n    var CURRENT_VMP_HIGH = LIMIT_VMP_HIGH_BASE;\n    var CURRENT_VOC_MAX  = LIMIT_VOC_MAX_BASE;\n\n    \/\/ ------------------------------------\n    \/\/ Panel map\n    \/\/ ------------------------------------\n    function buildPanelMap(list) {\n      var map = {};\n      (list || []).forEach(function (p) {\n        if (p && typeof p.id !== 'undefined') {\n          map[String(p.id)] = p;\n        }\n      });\n      return map;\n    }\n\n    (panelsList || []).forEach(function (p, idx) {\n      if (!p) return;\n      if (typeof p.id === 'undefined' || p.id === null || p.id === '') {\n        p.id = String(idx);\n      }\n    });\n\n    var panelMap = buildPanelMap(panelsList);\n\n    var form = byId('ssoCalculatorForm');\n    if (!form) return;\n\nfunction applyImpRules(imp) {\n  CURRENT_VMP_HIGH = LIMIT_VMP_HIGH_BASE;\n  CURRENT_VOC_MAX  = LIMIT_VOC_MAX_BASE;\n\n  if (!isFinite(imp)) return;\n  if (imp > LIMIT_IMP_MAX) return;\n\n  if (imp > LIMIT_IMP_NO_LIMIT) {\n    var reduceAmps = Math.min(imp, LIMIT_IMP_REDUCE_UNTIL) - LIMIT_IMP_NO_LIMIT;\n    if (reduceAmps < 0) reduceAmps = 0;\n\n    \/\/ Ny logik: 8 V per p\u00e5b\u00f6rjad 0,1 A \u00f6verstigande\n    var steps = Math.ceil((reduceAmps \/ LIMIT_IMP_REDUCE_STEP_A) - 1e-9);\n    if (steps < 0) steps = 0;\n\n    var reduced = LIMIT_VMP_HIGH_BASE - (LIMIT_IMP_REDUCE_STEP_V * steps);\n    if (reduced < 0) reduced = 0;\n    CURRENT_VMP_HIGH = reduced;\n  }\n\n  if (imp > LIMIT_IMP_REDUCE_UNTIL && imp <= LIMIT_IMP_MAX) {\n    CURRENT_VOC_MAX = LIMIT_VOC_MAX_REDUCED;\n  }\n}\n\n    \/\/ ------------------------------------\n    \/\/ Inputs\n    \/\/ ------------------------------------\n    var numPanelsInput   = byId('ssoNumPanels');\n    var mountTypeInput   = byId('ssoMountType');\n\n    var panelSelect      = byId('ssoPanelSelect');\n    var manualModelInput = byId('ssoManualModel');\n    var manualModelGroup = byId('ssoManualModelGroup');\n\n    var vmpInput         = byId('ssoPanelVmp');\n    var vocInput         = byId('ssoPanelVoc');\n    var impInput         = byId('ssoPanelImp');\n    var iscInput         = byId('ssoPanelIsc');\n    var vocCoeffInput    = byId('ssoPanelVocCoeff');\n    var pmaxInput        = byId('ssoPanelPmax');\n\n    var minTempInput     = byId('ssoMinTemperature');\n    var maxTempInput     = byId('ssoMaxTemperature');\n\n    var calcButton       = byId('ssoCalcButton');\n    var afterCalcWrap    = byId('ssoAfterCalc');\n    var exportButton     = byId('ssoExportButton');\n\n    var manualSsoToggle   = byId('ssoManualSsoToggle');\n    var manualSsoWrapper  = byId('ssoManualSsoWrapper');\n    var manualNumSsoInput = byId('ssoManualNumSso');\n\n    \/\/ ------------------------------------\n    \/\/ Result elements\n    \/\/ ------------------------------------\n    var resultDetailsBox  = byId('ssoResultDetails');\n    var dimensionNoteEl   = byId('ssoDimensionNote');\n\n    var elInstalledPower  = byId('ssoResInstalledPower');\n    var elNumSso          = byId('ssoResNumSso');\n    var elMinPanelsPerSso = byId('ssoResMinPanelsPerSso');\n    var elMaxPanelsPerSso = byId('ssoResMaxPanelsPerSso');\n    var elMinMaxPanelsPerSso = byId('ssoResMinMaxPanelsPerSso');\n    var elDistributionLines  = byId('ssoDistributionLines');\n\n    var elVocMax          = byId('ssoResVocMax');\n    var elVmpNominal      = byId('ssoResVmpNominal');\n    var elVmpMin          = byId('ssoResVmpMin');\n    var elVmpMax          = byId('ssoResVmpMax');\n\n    var elImp             = byId('ssoResImp');\n    var elIsc             = byId('ssoResIsc');\n    var elDimension       = byId('ssoResDimension');\n\n    \/\/ ------------------------------------\n    \/\/ State\n    \/\/ ------------------------------------\n    var hasCalculated = false;\n    var latestResult = null;\n    var latestRecommendedNumSso = null;\n    var manualSsoActiveLast = false;\n    var isExportingPdf = false;\n\n    \/\/ ------------------------------------\n    \/\/ Visibility\n    \/\/ ------------------------------------\n    function setAfterCalcVisibility(isVisible) {\n  if (!afterCalcWrap) return;\n\n  if (isVisible) {\n    afterCalcWrap.style.setProperty('display', 'block', 'important');\n  } else {\n    afterCalcWrap.style.setProperty('display', 'none', 'important');\n  }\n}\n\n    function setResultVisibility(isVisible) {\n      if (resultDetailsBox) resultDetailsBox.style.display = isVisible ? '' : 'none';\n\n      if (!isVisible) {\n        clearDimensionNote();\n      }\n\n      setAdvancedToggleAvailable(!!isVisible);\n      if (!isVisible) setAdvancedOpen(false);\n    }\n\nfunction setExportVisibility(isVisible) {\n  if (!exportButton) return;\n\n  if (isVisible) {\n    exportButton.style.setProperty('display', 'inline-flex', 'important');\n  } else {\n    exportButton.style.setProperty('display', 'none', 'important');\n  }\n  exportButton.disabled = !isVisible;\n}\n\n    function invalidateCalculation() {\n      hasCalculated = false;\n      latestResult = null;\n\n      setAfterCalcVisibility(false);\n      setResultVisibility(false);\n      setExportVisibility(false);\n\n      clearDimensionNote();\n    }\n\n    function runCalculationFromButton() {\n      hasCalculated = true;\n\n      setAfterCalcVisibility(true);\n      setResultVisibility(true);\n\n      if (manualSsoToggle && manualSsoToggle.checked) {\n        normalizeManualNumSsoInput();\n      }\n\n      calculate();\n\n      if (latestResult) {\n        setExportVisibility(true);\n\n        setTimeout(function () {\n          scrollToElement(afterCalcWrap || resultDetailsBox);\n        }, 0);\n      } else {\n        invalidateCalculation();\n      }\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Flags\n    \/\/ ------------------------------------\n    var flags;\n    function resetFlags() {\n      flags = {\n        vmpNomRed: false,\n        vmpMinRed: false,\n        vmpMaxRed: false,\n        vocRed: false,\n        impYellow: false,\n        impRed: false,\n        iscYellow: false,\n        manualSso: false\n      };\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Panel inputs readonly and fill\n    \/\/ ------------------------------------\n    function setPanelInputsReadOnly(flag) {\n      [vmpInput, vocInput, impInput, iscInput, vocCoeffInput, pmaxInput].forEach(function (el) {\n        if (!el) return;\n        el.readOnly = flag;\n      });\n    }\n\n    function setPanelInputsFromPanel(panel) {\n      if (!panel) {\n        if (pmaxInput) pmaxInput.value = '';\n        if (vmpInput) vmpInput.value = '';\n        if (vocInput) vocInput.value = '';\n        if (impInput) impInput.value = '';\n        if (iscInput) iscInput.value = '';\n        if (vocCoeffInput) vocCoeffInput.value = '';\n        return;\n      }\n\n      if (pmaxInput) pmaxInput.value = panel.pmax != null ? panel.pmax : '';\n      if (vmpInput) vmpInput.value = panel.vmp != null ? panel.vmp : '';\n      if (vocInput) vocInput.value = panel.voc != null ? panel.voc : '';\n      if (impInput) impInput.value = panel.imp != null ? panel.imp : '';\n      if (iscInput) iscInput.value = panel.isc != null ? panel.isc : '';\n      if (vocCoeffInput) {\n        vocCoeffInput.value = panel.voc_temp_coeff != null\n          ? Number(panel.voc_temp_coeff).toFixed(3)\n          : '';\n      }\n    }\n\n    function handlePanelSelectionChange() {\n      if (!panelSelect) return;\n\n      var panelId = panelSelect.value;\n      var isManual = panelId === 'manual';\n\n      if (isManual) {\n        if (manualModelGroup) manualModelGroup.style.display = '';\n        setPanelInputsReadOnly(false);\n        if (!vmpInput.value && !vocInput.value && !impInput.value && !iscInput.value) {\n          setPanelInputsFromPanel(null);\n        }\n      } else {\n        if (manualModelGroup) manualModelGroup.style.display = 'none';\n        setPanelInputsReadOnly(true);\n\n        if (panelId && panelMap[panelId]) setPanelInputsFromPanel(panelMap[panelId]);\n        else setPanelInputsFromPanel(null);\n      }\n\n      var hasRealPanelSelected = !!(panelId && panelId !== 'manual' && panelMap[panelId]);\n      var isManualSelected = (panelId === 'manual');\n\n      setPanelDataToggleAvailable(hasRealPanelSelected || isManualSelected);\n\n      setPanelDataOpen(isManualSelected);\n\n      invalidateCalculation();\n    }\n\n    function buildPanelForCalculation() {\n      if (!panelSelect) return null;\n\n      var panelId = panelSelect.value;\n      var isManual = panelId === 'manual';\n\n      if (isManual) {\n        return {\n          model: (manualModelInput && manualModelInput.value) ? manualModelInput.value : 'Annan panel (manuell)',\n          vmp: toNumber(vmpInput.value),\n          voc: toNumber(vocInput.value),\n          imp: toNumber(impInput.value),\n          isc: toNumber(iscInput.value),\n          voc_temp_coeff: toNumber(vocCoeffInput.value),\n          pmax: toNumber(pmaxInput.value)\n        };\n      }\n\n      if (!panelId || !panelMap[panelId]) return null;\n      return panelMap[panelId];\n    }\n\n    \/\/ ------------------------------------\n    \/\/ Styling\n    \/\/ ------------------------------------\n    function styleVmpNomCell(cell, value) {\n      if (!cell) return;\n      cell.style.backgroundColor = '';\n      cell.style.color = '';\n\n      if (!isFinite(value)) {\n        cell.textContent = 'Ej ber\u00e4knat';\n        flags.vmpNomRed = false;\n        return;\n      }\n\n      var text = formatNumber(value, 0) + ' V';\n      if (value < LIMIT_VMP_LOW || value > CURRENT_VMP_HIGH) {\n        flags.vmpNomRed = true;\n        cell.textContent = text;\n        cell.style.backgroundColor = '#c00000';\n        cell.style.color = '#fff';\n      } else {\n        flags.vmpNomRed = false;\n        cell.textContent = text;\n      }\n    }\n\n    function styleVmpMinMaxCell(cell, value, isMin) {\n      if (!cell) return;\n      cell.style.backgroundColor = '';\n      cell.style.color = '';\n\n      if (!isFinite(value)) {\n        cell.textContent = 'Ej ber\u00e4knat';\n        if (isMin) flags.vmpMinRed = false;\n        else flags.vmpMaxRed = false;\n        return;\n      }\n\n      var text = formatNumber(value, 0) + ' V';\n      if (value < LIMIT_VMP_LOW || value > CURRENT_VMP_HIGH) {\n        cell.textContent = text;\n        cell.style.backgroundColor = '#c00000';\n        cell.style.color = '#fff';\n        if (isMin) flags.vmpMinRed = true;\n        else flags.vmpMaxRed = true;\n      } else {\n        cell.textContent = text;\n        if (isMin) flags.vmpMinRed = false;\n        else flags.vmpMaxRed = false;\n      }\n    }\n\n    function styleVocCell(cell, value) {\n      var isRed = isFinite(value) && (value > CURRENT_VOC_MAX);\n      flags.vocRed = isRed;\n\n      if (!cell) return;\n\n      cell.style.backgroundColor = '';\n      cell.style.color = '';\n\n      if (!isFinite(value)) {\n        cell.textContent = 'Ej ber\u00e4knat';\n        return;\n      }\n\n      var text = formatNumber(value, 0) + ' V';\n      if (isRed) {\n        cell.textContent = text;\n        cell.style.backgroundColor = '#c00000';\n        cell.style.color = '#fff';\n      } else {\n        cell.textContent = text;\n      }\n    }\n\nfunction styleCurrentImp(cell, value) {\n  if (!cell) return;\n  cell.style.backgroundColor = '';\n  cell.style.color = '';\n\n  \/\/ Gul ska bort helt\n  flags.impYellow = false;\n  flags.impRed = false;\n\n  if (!isFinite(value)) {\n    cell.textContent = 'Ej ber\u00e4knat';\n    return;\n  }\n\n  \/\/ Inom \"utan begr\u00e4nsning\"\n  if (value <= LIMIT_IMP_NO_LIMIT) {\n    cell.textContent = formatNumber(value, 1) + ' A';\n    return;\n  }\n\n  \/\/ Mellan LIMIT_IMP_NO_LIMIT och LIMIT_IMP_MAX: visa normalt, ingen f\u00e4rg\n  if (value > LIMIT_IMP_NO_LIMIT && value <= LIMIT_IMP_MAX) {\n    cell.textContent = formatNumber(value, 1) + ' A';\n    return;\n  }\n\n  \/\/ \u00d6ver max: r\u00f6d varning kvar\n  flags.impRed = true;\n  cell.textContent = formatNumber(value, 1) + ' A';\n  cell.style.backgroundColor = '#c00000';\n  cell.style.color = '#fff';\n}\n\n\nfunction styleCurrentIsc(cell, value) {\n  if (!cell) return;\n  cell.style.backgroundColor = '';\n  cell.style.color = '';\n\n  \/\/ Gul ska bort helt\n  flags.iscYellow = false;\n\n  if (!isFinite(value)) {\n    cell.textContent = 'Ej ber\u00e4knat';\n    return;\n  }\n\n  \/\/ Visa alltid normalt, oavsett niv\u00e5\n  cell.textContent = formatNumber(value, 1) + ' A';\n}\n\n\n\n    \n    \n    \n    function buildDimensionBodyText(yellowReasons, redReasons) {\n  var lines = [];\n\n  if (yellowReasons && yellowReasons.length) {\n    lines.push(\"Note:\");\n    for (var i = 0; i < yellowReasons.length; i++) lines.push(\"- \" + yellowReasons[i]);\n  }\n\n  if (redReasons && redReasons.length) {\n    if (lines.length) lines.push(\"\"); \/\/ tom rad mellan block\n    lines.push(\"Unauthorized values:\");\n    for (var j = 0; j < redReasons.length; j++) lines.push(\"- \" + redReasons[j]);\n  }\n\n  return lines.join(\"\\n\");\n}\n\nfunction renderDimensionBox(cell, ok, titleText, bodyText) {\n  if (!cell) return;\n\n  \/\/ Beh\u00e5ll dina befintliga ok\/bad-klasser (de styr f\u00e4rg via CSS)\n  cell.classList.toggle(\"is-ok\", !!ok);\n  cell.classList.toggle(\"is-bad\", !ok);\n\n  var iconOk =\n    '<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n      '<path d=\"M20 6L9 17l-5-5\" stroke=\"#2e7d32\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/>' +\n    \"<\/svg>\";\n\n  var iconBad =\n    '<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n      '<path d=\"M18 6L6 18\" stroke=\"#c00000\" stroke-width=\"3\" stroke-linecap=\"round\"\/>' +\n      '<path d=\"M6 6l12 12\" stroke=\"#c00000\" stroke-width=\"3\" stroke-linecap=\"round\"\/>' +\n    \"<\/svg>\";\n\n  var icon = ok ? iconOk : iconBad;\n\n  \/\/ Rendera rubrikrad + f\u00f6rklaring under (ingen bold i br\u00f6dtext)\n  var safeBody = (bodyText || \"\").replace(\/&\/g, \"&amp;\").replace(\/<\/g, \"&lt;\").replace(\/>\/g, \"&gt;\");\n  safeBody = safeBody.replace(\/\\n\/g, \"<br>\");\n\n  cell.innerHTML =\n    '<div class=\"sso-dimension-title-row\">' +\n      '<span class=\"sso-dimension-title-text\">' + String(titleText || \"\") + \"<\/span>\" +\n      '<span class=\"sso-dimension-icon\" aria-hidden=\"true\">' + icon + \"<\/span>\" +\n    \"<\/div>\" +\n    (safeBody\n      ? '<div class=\"sso-dimension-body\">' + safeBody + \"<\/div>\"\n      : \"\");\n\n  cell.setAttribute(\"aria-label\", String(titleText || \"\"));\n}\n\n\n\n\n\n\n\n    \/\/ ------------------------------------\n    \/\/ Calculation\n    \/\/ ------------------------------------\n    function calculate() {\n      var panel = buildPanelForCalculation();\n      if (!panel) {\n        latestResult = null;\n        clearDimensionNote();\n        return;\n      }\n\n      resetFlags();\n\n      var numPanels = toNumber(numPanelsInput && numPanelsInput.value);\n      var vmp   = toNumber(panel.vmp);\n      var voc   = toNumber(panel.voc);\n      var imp   = toNumber(panel.imp);\n      var isc   = toNumber(panel.isc);\n      var coeff = toNumber(panel.voc_temp_coeff);\n      var pmax  = toNumber(panel.pmax);\n\n      applyImpRules(imp);\n\n      var baseMinTemp = toNumber(minTempInput && minTempInput.value);\n      var baseMaxTemp = toNumber(maxTempInput && maxTempInput.value);\n\n      var delta = 0;\n      var mt = mountTypeInput ? mountTypeInput.value : '';\n      if (mt === 'tak') delta = 5;\n      else if (mt === 'fasad') delta = 10;\n\n      var minTemp = isFinite(baseMinTemp) ? baseMinTemp + delta : NaN;\n      var maxTemp = isFinite(baseMaxTemp) ? baseMaxTemp + delta : NaN;\n\n      var k = isFinite(coeff) ? coeff \/ 100 : 0;\n      var tRef = 25;\n\n      var dTcold = isFinite(minTemp) ? (minTemp - tRef) : 0;\n      var dThot  = isFinite(maxTemp) ? (maxTemp - tRef) : 0;\n\n      var panelVmpCold = isFinite(vmp) ? vmp * (1 + k * dTcold) : NaN;\n      var panelVmpHot  = isFinite(vmp) ? vmp * (1 + k * dThot) : NaN;\n\n      var panelVmpMax = (isFinite(panelVmpCold) && isFinite(panelVmpHot))\n        ? Math.max(panelVmpCold, panelVmpHot)\n        : NaN;\n\n      var panelVocCold = isFinite(voc) ? voc * (1 + k * dTcold) : NaN;\n\n      var minPanelsPerSso = (isFinite(vmp) && vmp > 0)\n        ? Math.max(1, Math.ceil(LIMIT_VMP_LOW \/ vmp))\n        : NaN;\n\n      var maxPanels_nom = (isFinite(vmp) && vmp > 0)\n        ? Math.floor(CURRENT_VMP_HIGH \/ vmp)\n        : NaN;\n\n      var maxPanels_vmpMax = (isFinite(panelVmpMax) && panelVmpMax > 0)\n        ? Math.floor(CURRENT_VMP_HIGH \/ panelVmpMax)\n        : NaN;\n\n      var maxPanels_voc = (isFinite(panelVocCold) && panelVocCold > 0)\n        ? Math.floor(CURRENT_VOC_MAX \/ panelVocCold)\n        : NaN;\n\n      var maxPanelsPerSso = Math.min(maxPanels_nom, maxPanels_vmpMax, maxPanels_voc);\n      if (!isFinite(maxPanelsPerSso) || maxPanelsPerSso < 1) maxPanelsPerSso = NaN;\n\n      var numSsoRecommended = (isFinite(numPanels) && isFinite(maxPanelsPerSso) && maxPanelsPerSso > 0)\n        ? Math.ceil(numPanels \/ maxPanelsPerSso)\n        : NaN;\n\n      latestRecommendedNumSso = isFinite(numSsoRecommended) ? numSsoRecommended : null;\n\n      var useManualSso = manualSsoToggle && manualSsoToggle.checked;\n      var manualNumSso = NaN;\n\n      if (useManualSso) {\n        var raw = String((manualNumSsoInput && manualNumSsoInput.value) || '').trim();\n        if (raw) {\n          var n = toNumber(raw);\n          manualNumSso = (isFinite(n) && n > 0) ? Math.ceil(n) : NaN;\n        }\n      }\n\n      var numSsoUsed;\n      if (useManualSso && isFinite(manualNumSso) && manualNumSso > 0) {\n        numSsoUsed = manualNumSso;\n        flags.manualSso = true;\n      } else {\n        numSsoUsed = numSsoRecommended;\n        flags.manualSso = false;\n      }\n\n      var dist = getIntegerDistribution(numPanels, numSsoUsed);\n      if (!dist) {\n        latestResult = null;\n        clearDimensionNote();\n        return;\n      }\n\n      var panelsPerSsoWorst = dist.ceilPanels;\n\n      var stringVmpNomWorst  = (isFinite(vmp) && isFinite(panelsPerSsoWorst)) ? vmp * panelsPerSsoWorst : NaN;\n      var stringVmpColdWorst = (isFinite(panelVmpCold) && isFinite(panelsPerSsoWorst)) ? panelVmpCold * panelsPerSsoWorst : NaN;\n      var stringVmpHotWorst  = (isFinite(panelVmpHot) && isFinite(panelsPerSsoWorst)) ? panelVmpHot * panelsPerSsoWorst : NaN;\n\n      var ssoVmpMinWorst = (isFinite(stringVmpColdWorst) && isFinite(stringVmpHotWorst))\n        ? Math.min(stringVmpColdWorst, stringVmpHotWorst)\n        : NaN;\n\n      var ssoVmpMaxWorst = (isFinite(stringVmpColdWorst) && isFinite(stringVmpHotWorst))\n        ? Math.max(stringVmpColdWorst, stringVmpHotWorst)\n        : NaN;\n\n      var stringVocColdWorst = (isFinite(panelVocCold) && isFinite(panelsPerSsoWorst))\n        ? panelVocCold * panelsPerSsoWorst\n        : NaN;\n\n      var installedKw = (isFinite(pmax) && isFinite(numPanels)) ? (pmax * numPanels) \/ 1000 : NaN;\n\n      if (elInstalledPower) elInstalledPower.textContent = isFinite(installedKw) ? formatNumber(installedKw, 1) + ' kW' : '-';\n\n      if (elNumSso) {\n        if (isFinite(numSsoUsed)) elNumSso.textContent = flags.manualSso ? (numSsoUsed + ' st') : (numSsoUsed + ' st');\n        else elNumSso.textContent = '-';\n      }\n\n      if (elMinMaxPanelsPerSso) {\n  if (isFinite(minPanelsPerSso) && isFinite(maxPanelsPerSso)) {\n    elMinMaxPanelsPerSso.textContent = minPanelsPerSso + '\/' + maxPanelsPerSso + ' st';\n  } else {\n    elMinMaxPanelsPerSso.textContent = '-';\n  }\n}\n\nif (elDistributionLines) {\n  elDistributionLines.innerHTML = '';\n\n  if (isFinite(numSsoUsed) && numSsoUsed > 0 && dist) {\n    var ns = Math.round(numSsoUsed);\n\n    \/\/ Antal SSO med ceilPanels respektive floorPanels\n    var countCeil  = Math.max(0, Math.min(ns, Math.round(dist.numCeilStrings || 0)));\n    var countFloor = Math.max(0, ns - countCeil);\n\n    function appendRangeRow(startIdx, endIdx, panelsCount) {\n      if (!(startIdx > 0 && endIdx >= startIdx)) return;\n\n      var row = document.createElement('div');\n      row.className = 'sso-result-line';\n\n      var left = document.createElement('div');\n      left.className = 'sso-result-label';\n\n      var rangeText = (startIdx === endIdx)\n        ? String(startIdx)\n        : (startIdx + '-' + endIdx);\n\n      left.textContent = 'Recommended string allocation ' + rangeText;\n\n      var right = document.createElement('div');\n      right.className = 'sso-result-value';\n      right.textContent = panelsCount + ' panels';\n\n      row.appendChild(left);\n      row.appendChild(right);\n      elDistributionLines.appendChild(row);\n    }\n\n    \/\/ I din befintliga logik \u00e4r SSO 1..numCeilStrings = ceilPanels, resten = floorPanels\n    if (countCeil > 0) {\n      appendRangeRow(1, countCeil, dist.ceilPanels);\n    }\n\n    if (countFloor > 0) {\n      appendRangeRow(countCeil + 1, countCeil + countFloor, dist.floorPanels);\n    }\n  }\n}\n\n      styleVmpNomCell(elVmpNominal, stringVmpNomWorst);\n      styleVmpMinMaxCell(elVmpMin, ssoVmpMinWorst, true);\n      styleVmpMinMaxCell(elVmpMax, ssoVmpMaxWorst, false);\n      styleVocCell(elVocMax, stringVocColdWorst);\n      styleCurrentImp(elImp, imp);\n      styleCurrentIsc(elIsc, isc);\n\n      var vmpNomOk = isFinite(stringVmpNomWorst) &&\n        stringVmpNomWorst >= LIMIT_VMP_LOW &&\n        stringVmpNomWorst <= CURRENT_VMP_HIGH;\n\n      var vmpMinMaxOk = isFinite(ssoVmpMinWorst) && isFinite(ssoVmpMaxWorst) &&\n        ssoVmpMinWorst >= LIMIT_VMP_LOW &&\n        ssoVmpMaxWorst <= CURRENT_VMP_HIGH;\n\n      var impOk = isFinite(imp) && imp <= LIMIT_IMP_MAX;\n      var vocOk = isFinite(stringVocColdWorst) && stringVocColdWorst <= CURRENT_VOC_MAX;\n\n      var dimensionOk = vmpNomOk && vmpMinMaxOk && impOk && vocOk;\n\n\n\n\n\nvar starNeeded =\n  flags.vmpNomRed || flags.vmpMinRed || flags.vmpMaxRed ||\n  flags.vocRed || flags.impRed;\n\n\/\/ -----------------------------\n\/\/ Explanations shown in the same box as Result OK \/ Non\u2011permitted values\n\/\/ -----------------------------\nvar yellowReasons = [];\nvar redReasons = [];\n\nif (flags.manualSso && isFinite(numSsoUsed)) {\n  yellowReasons.push(\n    \"Number of SSO (\" + numSsoUsed + \" pcs) is manually selected and may differ from the calculator recommendation.\"\n  );\n}\n\nif (flags.vmpMinRed && isFinite(ssoVmpMinWorst)) {\n  redReasons.push(\n    \"Vmp min (\" + formatNumber(ssoVmpMinWorst, 0) + \" V) is outside the operating range \" +\n    formatNumber(LIMIT_VMP_LOW, 0) + \" to \" +\n    formatNumber(CURRENT_VMP_HIGH, 0) + \" V.\"\n  );\n}\n\nif (flags.vmpMaxRed && isFinite(ssoVmpMaxWorst)) {\n  redReasons.push(\n    \"Vmp max (\" + formatNumber(ssoVmpMaxWorst, 0) + \" V) is outside the operating range \" +\n    formatNumber(LIMIT_VMP_LOW, 0) + \" to \" +\n    formatNumber(CURRENT_VMP_HIGH, 0) + \" V.\"\n  );\n}\n\nif (flags.vmpNomRed && isFinite(stringVmpNomWorst)) {\n  redReasons.push(\n    \"Vmp nominal (\" + formatNumber(stringVmpNomWorst, 0) + \" V) is outside the operating range \" +\n    formatNumber(LIMIT_VMP_LOW, 0) + \" to \" +\n    formatNumber(CURRENT_VMP_HIGH, 0) + \" V.\"\n  );\n}\n\nif (flags.vocRed && isFinite(stringVocColdWorst)) {\n  redReasons.push(\n    \"Voc (\" + formatNumber(stringVocColdWorst, 0) + \" V) is above the maximum string voltage \" +\n    formatNumber(CURRENT_VOC_MAX, 0) + \" V.\"\n  );\n}\n\nif (flags.impRed && isFinite(imp)) {\n  redReasons.push(\n    \"Imp (\" + formatNumber(imp, 1) + \" A) is above \" +\n    formatNumber(LIMIT_IMP_MAX, 1) + \" A. Not allowed.\"\n  );\n}\n\n\/\/ -----------------------------\n\/\/ Render everything into the same box (#ssoResDimension)\n\/\/ -----------------------------\nvar titleText = dimensionOk\n  ? \"Result OK\"\n  : \"Result contains non\u2011permitted values\";\n\nvar bodyText = buildDimensionBodyText(yellowReasons, redReasons);\n\n\/\/ Always show title, body only if it has content\nrenderDimensionBox(elDimension, dimensionOk, titleText, bodyText);\n\n\/\/ Hide old note box completely (if still in DOM)\nif (dimensionNoteEl) {\n  dimensionNoteEl.style.display = \"none\";\n  dimensionNoteEl.textContent = \"\";\n}\n\nlatestResult = {\n  panel: panel,\n  num_panels: isFinite(numPanels) ? Math.round(numPanels) : null,\n  installed_kw: isFinite(installedKw) ? installedKw : null,\n  num_sso: isFinite(numSsoUsed) ? Math.round(numSsoUsed) : null,\n  min_panels_sso: isFinite(minPanelsPerSso) ? minPanelsPerSso : null,\n  max_panels_sso: isFinite(maxPanelsPerSso) ? maxPanelsPerSso : null,\n\n  distribution: dist,\n  panels_per_sso_worst: isFinite(panelsPerSsoWorst) ? panelsPerSsoWorst : null,\n\n  voc_cold_v: isFinite(stringVocColdWorst) ? stringVocColdWorst : null,\n  vmp_nom_v: isFinite(stringVmpNomWorst) ? stringVmpNomWorst : null,\n  vmp_min_v: isFinite(ssoVmpMinWorst) ? ssoVmpMinWorst : null,\n  vmp_max_v: isFinite(ssoVmpMaxWorst) ? ssoVmpMaxWorst : null,\n\n  imp_a: isFinite(imp) ? imp : null,\n  isc_a: isFinite(isc) ? isc : null,\n  dimension_ok: dimensionOk,\n  flags: JSON.parse(JSON.stringify(flags)),\n  yellowReasons: yellowReasons.slice(),\n  redReasons: redReasons.slice()\n};\n\n}\n\n\/\/ ------------------------------------\n\/\/ Manual SSO toggle\n\/\/ ------------------------------------\nfunction handleManualSsoToggle() {\n  if (!manualSsoWrapper || !manualSsoToggle) return;\n\n  var nowActive = manualSsoToggle.checked;\n\n  if (nowActive) {\n    manualSsoWrapper.style.display = \"\";\n    if (!manualSsoActiveLast && latestRecommendedNumSso != null && manualNumSsoInput) {\n      manualNumSsoInput.value = latestRecommendedNumSso;\n    }\n  } else {\n    manualSsoWrapper.style.display = \"none\";\n  }\n\n  manualSsoActiveLast = nowActive;\n\n  if (hasCalculated) {\n    calculate();\n    setAfterCalcVisibility(true);\n    setResultVisibility(true);\n    setExportVisibility(!!latestResult);\n  }\n}\n\n\/\/ ------------------------------------\n\/\/ Print sheet fill\n\/\/ ------------------------------------\nfunction fillPrintSheet() {\n  if (!latestResult) return;\n\n  var p = latestResult.panel || {};\n\n  function setText(id, text) {\n    var el = byId(id);\n    if (el) el.textContent = (text == null ? \"\" : String(text));\n  }\n\n  function mountTypeLabel(v){\n    if (v === \"tak\") return \"Roof mounting\";\n    if (v === \"mark\") return \"Ground mounting\";\n    if (v === \"fasad\") return \"Fa\u00e7ade mounting\";\n    return \"-\";\n  }\n\n  var projectInput = byId(\"ssoProjectName\");\n  var projectName = projectInput && projectInput.value ? projectInput.value.trim() : \"\";\n  setText(\"ssoPdfProjectName\", projectName || \"-\");\n\n  var now = new Date();\n  var y = now.getFullYear();\n  var m = String(now.getMonth() + 1).padStart(2, \"0\");\n  var d = String(now.getDate()).padStart(2, \"0\");\n  setText(\"ssoPdfDate\", y + \"-\" + m + \"-\" + d);\n\n  var modelName = p.model || p.modell || \"-\";\n  setText(\"ssoPdfPanelModel\", modelName);\n\n  setText(\"ssoPdfPanelCount\", latestResult.num_panels != null ? latestResult.num_panels : \"-\");\n  setText(\"ssoPdfMountType\", mountTypeLabel(mountTypeInput ? mountTypeInput.value : \"\"));\n\n  var baseMinTemp = toNumber(minTempInput && minTempInput.value);\n  var baseMaxTemp = toNumber(maxTempInput && maxTempInput.value);\n\n  var delta = 0;\n  var mt = mountTypeInput ? mountTypeInput.value : \"\";\n  if (mt === \"tak\") delta = 5;\n  else if (mt === \"fasad\") delta = 10;\n\n  var minTemp = isFinite(baseMinTemp) ? baseMinTemp + delta : NaN;\n  var maxTemp = isFinite(baseMaxTemp) ? baseMaxTemp + delta : NaN;\n\n  setText(\"ssoPdfMinTemp\", isFinite(minTemp) ? formatNumber(minTemp, 0) : \"-\");\n  setText(\"ssoPdfMaxTemp\", isFinite(maxTemp) ? formatNumber(maxTemp, 0) : \"-\");\n\n  setText(\"ssoPdfPanelPmax\", (p.pmax != null && isFinite(p.pmax)) ? formatNumber(p.pmax, 0) : \"-\");\n  setText(\"ssoPdfPanelVmp\",  (p.vmp != null && isFinite(p.vmp)) ? formatNumber(p.vmp, 2) : \"-\");\n  setText(\"ssoPdfPanelVoc\",  (p.voc != null && isFinite(p.voc)) ? formatNumber(p.voc, 1) : \"-\");\n  setText(\"ssoPdfPanelImp\",  (p.imp != null && isFinite(p.imp)) ? formatNumber(p.imp, 2) : \"-\");\n  setText(\"ssoPdfPanelIsc\",  (p.isc != null && isFinite(p.isc)) ? formatNumber(p.isc, 2) : \"-\");\n\n  if (p.voc_temp_coeff != null && isFinite(p.voc_temp_coeff)) {\n    setText(\"ssoPdfPanelVocCoeff\", formatNumber(toNumber(p.voc_temp_coeff), 2));\n  } else {\n    setText(\"ssoPdfPanelVocCoeff\", \"-\");\n  }\n\n  setText(\"ssoPdfSolarInstalled\", latestResult.installed_kw != null ? (formatNumber(latestResult.installed_kw, 1) + \" kW\") : \"-\");\n  setText(\"ssoPdfNumSso\", latestResult.num_sso != null ? (latestResult.num_sso + \" pcs\") : \"-\");\n\n  if (latestResult.min_panels_sso != null && latestResult.max_panels_sso != null) {\n    setText(\"ssoPdfMinMaxPanelsPerSso\", latestResult.min_panels_sso + \"\/\" + latestResult.max_panels_sso + \" pcs\");\n  } else {\n    setText(\"ssoPdfMinMaxPanelsPerSso\", \"-\");\n  }\n\n  setText(\"ssoPdfVmpNominal\", latestResult.vmp_nom_v != null ? (formatNumber(latestResult.vmp_nom_v, 0) + \" V\") : \"-\");\n  setText(\"ssoPdfVmpMin\",     latestResult.vmp_min_v != null ? (formatNumber(latestResult.vmp_min_v, 0) + \" V\") : \"-\");\n  setText(\"ssoPdfVmpMax\",     latestResult.vmp_max_v != null ? (formatNumber(latestResult.vmp_max_v, 0) + \" V\") : \"-\");\n  setText(\"ssoPdfVocMax\",     latestResult.voc_cold_v != null ? (formatNumber(latestResult.voc_cold_v, 0) + \" V\") : \"-\");\n\n  setText(\"ssoPdfImp\", latestResult.imp_a != null ? (formatNumber(latestResult.imp_a, 1) + \" A\") : \"-\");\n  setText(\"ssoPdfIsc\", latestResult.isc_a != null ? (formatNumber(latestResult.isc_a, 1) + \" A\") : \"-\");\n\n  var linesWrap = byId(\"ssoPdfDistributionLines\");\n  if (linesWrap) {\n    linesWrap.innerHTML = \"\";\n\n    var dist = latestResult.distribution;\n    if (dist && latestResult.num_sso != null) {\n      var ns = Math.round(latestResult.num_sso);\n      var countCeil  = Math.max(0, Math.min(ns, Math.round(dist.numCeilStrings || 0)));\n      var countFloor = Math.max(0, ns - countCeil);\n\n      function appendRangeRow(startIdx, endIdx, panelsCount) {\n        var row = document.createElement(\"div\");\n        row.className = \"tsPdfLine\";\n\n        var label = document.createElement(\"div\");\n        label.className = \"tsPdfLabel\";\n\n        var rangeText = (startIdx === endIdx) ? String(startIdx) : (startIdx + \"-\" + endIdx);\n        label.textContent = \"Recommended string allocation SSO \" + rangeText;\n\n        var value = document.createElement(\"div\");\n        value.className = \"tsPdfValue\";\n        value.textContent = panelsCount + \" panels\";\n\n        row.appendChild(label);\n        row.appendChild(value);\n        linesWrap.appendChild(row);\n      }\n\n      if (countCeil > 0) appendRangeRow(1, countCeil, dist.ceilPanels);\n      if (countFloor > 0) appendRangeRow(countCeil + 1, countCeil + countFloor, dist.floorPanels);\n    }\n  }\n\n  window.ssoPdfMeta = {\n    projectName: projectName,\n    dateToken: (function () {\n      var dt = new Date();\n      var yy = dt.getFullYear();\n      var mm = String(dt.getMonth() + 1).padStart(2, \"0\");\n      var dd = String(dt.getDate()).padStart(2, \"0\");\n      return \"\" + yy + mm + dd;\n    })()\n  };\n}\n\n\n\/\/ ------------------------------------\n\/\/ Export PDF (fix: prevent double run + prevent submit)\n\/\/ ------------------------------------\nasync function exportPdf(e) {\n  if (e && e.preventDefault) e.preventDefault();\n\n  if (isExportingPdf) return;\n  isExportingPdf = true;\n\n  try {\n    if (!hasCalculated || !latestResult) {\n      alert('Press \"Run calculation\" before creating a PDF.');\n      return;\n    }\n\n    if (!window.html2canvas) {\n      alert(\"The PDF function (html2canvas) is not loaded correctly.\");\n      return;\n    }\n\n    var JsPdfConstructor = null;\n    if (window.jspdf && window.jspdf.jsPDF) JsPdfConstructor = window.jspdf.jsPDF;\n    else if (window.jsPDF) JsPdfConstructor = window.jsPDF;\n\n    if (!JsPdfConstructor) {\n      alert(\"The PDF library (jsPDF) could not be loaded correctly.\");\n      return;\n    }\n\n    if (exportButton) exportButton.disabled = true;\n\n    fillPrintSheet();\n\n    var host = byId(\"ssoPdfHost\");\n    var tpl = byId(\"ssoPdfTemplate\");\n    if (!host || !tpl) {\n      alert(\"Could not find the PDF template (ssoPdfTemplate) or host (ssoPdfHost).\");\n      return;\n    }\n\n    host.style.position = \"fixed\";\n    host.style.left = \"-10000px\";\n    host.style.top = \"0\";\n    host.style.width = \"794px\";\n    host.style.background = \"#fff\";\n    host.style.pointerEvents = \"none\";\n    host.style.zIndex = \"2147483647\";\n    host.style.display = \"block\";\n    host.style.visibility = \"visible\";\n    host.style.opacity = \"1\";\n    host.style.height = \"auto\";\n    host.style.overflow = \"hidden\";\n\n    host.innerHTML = \"\";\n\n    var tplClone = tpl.cloneNode(true);\n    tplClone.classList.remove(\"ts-hidden\");\n    tplClone.setAttribute(\"aria-hidden\", \"false\");\n    tplClone.id = \"ssoPdfTemplateRender\";\n    host.appendChild(tplClone);\n\n    await forcePdfLogo(tplClone);\n\n    await new Promise(function (resolve) {\n      requestAnimationFrame(function () {\n        requestAnimationFrame(resolve);\n      });\n    });\n\n    var canvas = await html2canvas(tplClone, {\n      scale: 2,\n      backgroundColor: \"#ffffff\",\n      useCORS: true,\n      allowTaint: false,\n      scrollX: 0,\n      scrollY: 0,\n      windowWidth: 794\n    });\n\n    if (!canvas || !canvas.width || !canvas.height) {\n      alert(\"Could not create PDF because the canvas size is 0 px.\");\n      return;\n    }\n\n    var imgData = canvas.toDataURL(\"image\/jpeg\", 0.95);\n    var pdf = new JsPdfConstructor(\"p\", \"mm\", \"a4\");\n\n    var pdfWidth = pdf.internal.pageSize.getWidth();\n    var pdfHeight = pdf.internal.pageSize.getHeight();\n\n    var imgWidth = canvas.width;\n    var imgHeight = canvas.height;\n    var imgRatio = imgWidth \/ imgHeight;\n\n    var renderWidth = pdfWidth;\n    var renderHeight = renderWidth \/ imgRatio;\n\n    if (renderHeight > pdfHeight) {\n      renderHeight = pdfHeight;\n      renderWidth = renderHeight * imgRatio;\n    }\n\n    var x = (pdfWidth - renderWidth) \/ 2;\n    var y = 0;\n\n    pdf.addImage(imgData, \"JPEG\", x, y, renderWidth, renderHeight);\n\n    var projectInput = byId(\"ssoProjectName\");\n    var projectName = projectInput && projectInput.value ? projectInput.value : \"\";\n    var filename = buildPdfFilename(\"SSO_calculator\", projectName);\n\n    pdf.save(filename);\n  } catch (err) {\n    alert(\"Could not create PDF at this time.\");\n  } finally {\n    var hostFinally = byId(\"ssoPdfHost\");\n    if (hostFinally) hostFinally.innerHTML = \"\";\n    if (exportButton) exportButton.disabled = false;\n    isExportingPdf = false;\n  }\n}\n\n\n\n\n    \/\/ ------------------------------------\n    \/\/ Expose globals\n    \/\/ ------------------------------------\n    window.ssoExportPdf = exportPdf;\n    window.ssoFillPrintSheet = fillPrintSheet;\n\n    \/\/ ------------------------------------\n    \/\/ Events\n    \/\/ ------------------------------------\n    [\n      numPanelsInput,\n      minTempInput,\n      maxTempInput,\n      mountTypeInput,\n      manualModelInput,\n      vmpInput,\n      vocInput,\n      impInput,\n      iscInput,\n      vocCoeffInput,\n      pmaxInput\n    ].forEach(function (el) {\n      if (!el) return;\n      el.addEventListener('change', invalidateCalculation);\n      el.addEventListener('input', invalidateCalculation);\n    });\n\n    if (panelSelect) panelSelect.addEventListener('change', handlePanelSelectionChange);\n    if (calcButton) calcButton.addEventListener('click', runCalculationFromButton);\n\n    if (manualNumSsoInput) {\n      manualNumSsoInput.addEventListener('change', function () {\n        if (!hasCalculated) return;\n        calculate();\n        setAfterCalcVisibility(true);\n        setResultVisibility(true);\n        setExportVisibility(!!latestResult);\n      });\n\n      manualNumSsoInput.addEventListener('input', function () {\n        if (!hasCalculated) return;\n        calculate();\n        setAfterCalcVisibility(true);\n        setResultVisibility(true);\n        setExportVisibility(!!latestResult);\n      });\n\n      manualNumSsoInput.addEventListener('blur', function () {\n        if (!manualSsoToggle || !manualSsoToggle.checked) return;\n\n        normalizeManualNumSsoInput();\n\n        if (!hasCalculated) return;\n        calculate();\n        setAfterCalcVisibility(true);\n        setResultVisibility(true);\n        setExportVisibility(!!latestResult);\n      });\n    }\n\n    if (manualSsoToggle) manualSsoToggle.addEventListener('change', handleManualSsoToggle);\n    if (exportButton) {\n  exportButton.type = \"button\";\n  exportButton.addEventListener(\"click\", exportPdf);\n}\n\n    \/\/ ------------------------------------\n    \/\/ Init state\n    \/\/ ------------------------------------\n    setPanelInputsReadOnly(true);\n    handlePanelSelectionChange();\n\n    setAfterCalcVisibility(false);\n    setResultVisibility(false);\n    setExportVisibility(false);\n\n    setPanelDataOpen(false);\n    setAdvancedOpen(false);\n    setAdvancedToggleAvailable(false);\n\n    handleManualSsoToggle();\n    invalidateCalculation();\n  })();\n};\n<\/script>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-057cb69 elementor-widget elementor-widget-html\" data-id=\"057cb69\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<section id=\"hiddenRootsCable\" style=\"display:none;\">\r\n  <div id=\"cableCalculatorRoot\">\r\n    <section id=\"kabelkalkylatorPrint\" class=\"cable-calculator\">\r\n      <div class=\"cc-layout\">\r\n\r\n        <form id=\"cableCalculatorForm\" class=\"cc-form\">\r\n  <div class=\"ts-section ts-card cc-card\">\r\n<hr class=\"ps-summary-divider\">\r\n    <br>\r\n          <div class=\"cc-mode-switch\" role=\"group\" aria-label=\"Val av kabeltyp\">\r\n            <button type=\"button\" id=\"modeBtnFromLoad\" class=\"cc-mode-btn is-active\" aria-pressed=\"true\">New cable<\/button>\r\n            <button type=\"button\" id=\"modeBtnFromCable\" class=\"cc-mode-btn\" aria-pressed=\"false\">Existing cable<\/button>\r\n          <\/div>\r\n\r\n          <input class=\"cc-hidden-radio\" type=\"radio\" name=\"calc_mode\" id=\"modeFromLoad\" value=\"fromLoad\" checked>\r\n          <input class=\"cc-hidden-radio\" type=\"radio\" name=\"calc_mode\" id=\"modeFromCable\" value=\"fromCable\">\r\n\r\n          <div class=\"sso-label\"><strong>Cable A<\/strong><\/div>\r\n\r\n          <div class=\"sso-field-group\">\r\n            <label class=\"sso-label\" for=\"conductorConfigA\">Cable type<\/label>\r\n            <select id=\"conductorConfigA\" name=\"conductor_config_a\" class=\"sso-input\">\r\n              <option value=\"3\">3 conductors, L+, L-, PE<\/option>\r\n              <option value=\"4\">4 conductors, L+, L-, X, PE<\/option>\r\n              <option value=\"4_shield\">4 conductors with shield, 2xL+, 2xL-, PE = shield<\/option>\r\n              <option value=\"5\">5 conductors, 2xL+, 2xL-, PE<\/option>\r\n            <\/select>\r\n          <\/div>\r\n\r\n          <div class=\"sso-grid-3\">\r\n\r\n            <div class=\"sso-field-group\" id=\"powerFieldA\">\r\n              <label class=\"sso-label\" for=\"power\">Power<\/label>\r\n              <div class=\"sso-unit\">\r\n                <input id=\"power\" name=\"power_kw\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"ex 14\" value=\"\">\r\n                <span class=\"sso-unit-text\">kW<\/span>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\" id=\"knownCableFieldsA\" style=\"display:none;\">\r\n              <label class=\"sso-label\" for=\"knownCableTypeA\">Cable cross-section<\/label>\r\n              <select id=\"knownCableTypeA\" class=\"sso-input\"><\/select>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\">\r\n              <label class=\"sso-label\" for=\"length\">Cable lenght<\/label>\r\n              <div class=\"sso-unit\">\r\n                <input id=\"length\" name=\"length_m\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"ex 10\" value=\"\">\r\n                <span class=\"sso-unit-text\">m<\/span>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\">\r\n              <label class=\"sso-label\" for=\"maxDrop\">Max voltage drop<\/label>\r\n              <div class=\"sso-unit\">\r\n                <input id=\"maxDrop\" name=\"max_drop_percent\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"1\">\r\n                <span class=\"sso-unit-text\">%<\/span>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\">\r\n              <label class=\"sso-label\" for=\"ambientTemp\">Ambient temperature<\/label>\r\n              <div class=\"sso-unit\">\r\n                <input id=\"ambientTemp\" name=\"ambient_temp_c\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"30\">\r\n                <span class=\"sso-unit-text\">\u00b0C<\/span>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\">\r\n              <label class=\"sso-label\" for=\"installMethod\">Installation method<\/label>\r\n              <select id=\"installMethod\" name=\"install_method\" class=\"sso-input\">\r\n                <option value=\"A1\">A1, in wall, insulated<\/option>\r\n                <option value=\"A2\">A2, in wall, uninsulated or lightly insulated <\/option>\r\n                <option value=\"B1\">B1, in conduit in wall<\/option>\r\n                <option value=\"C\" selected>C, on wall or in free air<\/option>\r\n                <option value=\"D1\">D1, in ground, single cable<\/option>\r\n                <option value=\"D2\">D2, in ground, multiple cables<\/option>\r\n                <option value=\"E\">E, in conduit in ground<\/option>\r\n              <\/select>\r\n            <\/div>\r\n\r\n            <div class=\"sso-field-group\">\r\n              <label class=\"sso-label\" for=\"insulationType\">Cable insulation<\/label>\r\n              <select id=\"insulationType\" name=\"insulation_type\" class=\"sso-input\">\r\n                <option value=\"PVC70\">PVC 70 \u00b0C<\/option>\r\n                <option value=\"XLPE90\">XLPE 90 \u00b0C<\/option>\r\n              <\/select>\r\n            <\/div>\r\n\r\n          <\/div>\r\n\r\n          <div class=\"cc-series-wrap\" style=\"margin:0.5rem 0;\">\r\n\r\n            <div class=\"ts-toggle-block\">\r\n              <div class=\"ts-toggle-head\">\r\n                <div class=\"ts-toggle-label\">Add additional cable in series<\/div>\r\n                <label class=\"ts-switch\">\r\n                  <input type=\"checkbox\" id=\"seriesToggle\">\r\n                  <span class=\"ts-slider\" aria-hidden=\"true\"><\/span>\r\n                <\/label>\r\n              <\/div>\r\n            <\/div>\r\n\r\n            <div id=\"seriesInputs\" class=\"cc-series-inputs\" style=\"display:none;margin-top:0.5rem;padding-top:0.5rem;\">\r\n\r\n              <div class=\"sso-label\"><strong>Cable B<\/strong><\/div>\r\n\r\n              <div class=\"sso-field-group\">\r\n                <label class=\"sso-label\" for=\"conductorConfigB\">Kabeltyp<\/label>\r\n                <select id=\"conductorConfigB\" name=\"conductor_config_b\" class=\"sso-input\">\r\n                  <option value=\"3\">3 conductors, L+, L-, PE<\/option>\r\n                  <option value=\"4\">4 conductors, L+, L-, X, PE<\/option>\r\n                  <option value=\"4_shield\">4 conductors with shield, 2xL+, 2xL-, PE = shield<\/option>\r\n                  <option value=\"5\">5 conductors, 2xL+, 2xL-, PE<\/option>\r\n                <\/select>\r\n              <\/div>\r\n\r\n              <div class=\"sso-grid-3\">\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"power2\">Power<\/label>\r\n                  <div class=\"sso-unit\">\r\n                    <input id=\"power2\" name=\"power_kw2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"ex 8\" value=\"\">\r\n                    <span class=\"sso-unit-text\">kW<\/span>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"length2\">Cable lenght<\/label>\r\n                  <div class=\"sso-unit\">\r\n                    <input id=\"length2\" name=\"length_m2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"ex 5\" value=\"\">\r\n                    <span class=\"sso-unit-text\">m<\/span>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"maxDrop2\">Max voltage drop<\/label>\r\n                  <div class=\"sso-unit\">\r\n                    <input id=\"maxDrop2\" name=\"max_drop_percent2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"0.5\">\r\n                    <span class=\"sso-unit-text\">%<\/span>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"ambientTemp2\">Ambient temperature<\/label>\r\n                  <div class=\"sso-unit\">\r\n                    <input id=\"ambientTemp2\" name=\"ambient_temp_c2\" type=\"text\" class=\"sso-input sso-input-unit\" placeholder=\"0\" value=\"30\">\r\n                    <span class=\"sso-unit-text\">\u00b0C<\/span>\r\n                  <\/div>\r\n                <\/div>\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"installMethod2\">Installation method<\/label>\r\n                  <select id=\"installMethod2\" name=\"install_method2\" class=\"sso-input\">\r\n                    <option value=\"A1\">A1, in wall, insulated<\/option>\r\n                    <option value=\"A2\">A2, in wall, uninsulated or lightly insulated <\/option>\r\n                    <option value=\"B1\">B1, in conduit in wall<\/option>\r\n                    <option value=\"C\" selected>C, on wall or in free air<\/option>\r\n                    <option value=\"D1\">D1, in ground, single cable<\/option>\r\n                    <option value=\"D2\">D2, in ground, multiple cables<\/option>\r\n                    <option value=\"E\">E, in conduit in ground<\/option>\r\n                  <\/select>\r\n                <\/div>\r\n\r\n                <div class=\"sso-field-group\">\r\n                  <label class=\"sso-label\" for=\"insulationType2\">Cable insulation<\/label>\r\n                  <select id=\"insulationType2\" name=\"insulation_type2\" class=\"sso-input\">\r\n                    <option value=\"PVC70\">PVC 70 \u00b0C<\/option>\r\n                    <option value=\"XLPE90\">XLPE 90 \u00b0C<\/option>\r\n                  <\/select>\r\n                <\/div>\r\n\r\n              <\/div>\r\n\r\n            <\/div>\r\n          <\/div>\r\n<\/div>\r\n        <\/form>\r\n\r\n        <div class=\"cc-actions\" style=\"margin-top:14px; margin-bottom:14px\">\r\n          <button type=\"button\" class=\"cc-submit\" id=\"ccCalcBtn\">Run calculation <\/button>\r\n        <\/div>\r\n\r\n        <div id=\"ccResultWrap\" class=\"ts-hidden\" style=\"margin-top:16px;\">\r\n          <hr class=\"ps-summary-divider\">\r\n          <h6><strong>Cable calculation<\/strong><\/h6>\r\n          \r\n<div id=\"ccCalcAlert\"\r\n       style=\"display:none;margin-top:12px;border:1px solid #ffe1a6;background:#fff7e6;padding:10px 12px;border-radius:12px;font-size:13px;color:#5a3a00;\"><\/div>\r\n\r\n          <div class=\"sso-result-lines\" style=\"margin-top:12px;\">\r\n            <div class=\"sso-result-line\" id=\"ccLineA\" style=\"display:none;\">\r\n              <div class=\"sso-result-label\">Cable A<\/div>\r\n              <div class=\"sso-result-value\" id=\"ccResA\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-result-line\" id=\"ccLineB\" style=\"display:none;\">\r\n              <div class=\"sso-result-label\">Cable B<\/div>\r\n              <div class=\"sso-result-value\" id=\"ccResB\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"sso-result-line\" id=\"ccLineTotal\" style=\"display:none;\">\r\n              <div class=\"sso-result-label\">Voltage drop<\/div>\r\n              <div class=\"sso-result-value\" id=\"ccResTotal\">-<\/div>\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- =========================\r\nDOKUMENTATION + PDF (Kabelkalkylator)\r\n- Visas i vyn efter ber\u00e4kning\r\n- PDF renderas alltid via #tsSystemPdfHost (offscreen)\r\n========================= -->\r\n\r\n<section id=\"tsCableDocSection\" class=\"ts-section ts-card ts-hidden\">\r\n<br>\r\n  <hr class=\"ps-summary-divider\">\r\n  <h6><strong>Dokumentation<\/strong><\/h6>\r\n\r\n  <div class=\"sso-field-group\" style=\"margin-top:12px;\">\r\n    <label class=\"sso-label\" for=\"tsProjectName\">Project name<\/label>\r\n    <input class=\"sso-input\" id=\"tsProjectName\" name=\"project_name\" type=\"text\" placeholder=\"Enter project name...\">\r\n  <\/div>\r\n\r\n  <div class=\"sso-field-group ts-hidden\" id=\"tsCableNameRowA\">\r\n    <label class=\"sso-label\" for=\"tsCableNameA\">Name for Cable A<\/label>\r\n    <input class=\"sso-input\" id=\"tsCableNameA\" name=\"cable_name_a\" type=\"text\" placeholder=\"Enter name for cable A...\">\r\n  <\/div>\r\n\r\n  <div class=\"sso-field-group ts-hidden\" id=\"tsCableNameRowB\">\r\n    <label class=\"sso-label\" for=\"tsCableNameB\">Name for Cable B<\/label>\r\n    <input class=\"sso-input\" id=\"tsCableNameB\" name=\"cable_name_b\" type=\"text\" placeholder=\"Enter name for cable B...\">\r\n  <\/div>\r\n\r\n  <div class=\"cc-actions\" style=\"margin-top:14px; margin-bottom:14px;\">\r\n    <button type=\"button\" id=\"tsCreatePdfBtn\" class=\"cc-submit ts-create-pdf\" data-action=\"createPdf\">Create PDF<\/button>\r\n\r\n  <\/div>\r\n\r\n\r\n          <br>\r\n         <hr class=\"ps-summary-divider\">\r\n<div class=\"sso-notes\">\r\n  <div class=\"sso-notes-title\">Observera<\/div>\r\n  <ul class=\"sso-notes-list\">\r\n      <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\r\n      <li>Cable calculations are based on SS 436 40 00 and IEC 60364-5-52, with additional references to IEC 60228 and IEC 60269.<\/li>\r\n      <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\r\n  <\/ul>\r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n\r\n\r\n  \r\n  \r\n  \r\n\r\n<\/div>\r\n\r\n\r\n\r\n<\/section>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- =========================\r\nPDF TEMPLATE: Kabel (dold mall)\r\n- Struktur identisk med Systemkalkylatorns PDF\r\n- Beh\u00e5ller befintliga JS-IDn\r\n========================= -->\r\n<section id=\"tsCablePdfTemplate\" class=\"ts-hidden\" aria-hidden=\"true\">\r\n  <div class=\"tsPdfPage\" id=\"tsPdfPageCable\">\r\n\r\n    <!-- Header (identisk med system) -->\r\n    <div class=\"tsPdfHeader\">\r\n      <div class=\"tsPdfHeaderLeft\">\r\n        <div class=\"tsPdfTitle\">Cable documentation<\/div>\r\n\r\n        <div class=\"tsPdfMeta\">\r\n          <div class=\"tsPdfMetaRow\">\r\n            <div class=\"tsPdfMetaLabel\">Project name<\/div>\r\n            <div class=\"tsPdfMetaValue\" id=\"tsCablePdfProjectNameMini\">-<\/div>\r\n          <\/div>\r\n          <div class=\"tsPdfMetaRow\">\r\n            <div class=\"tsPdfMetaLabel\">Date<\/div>\r\n            <div class=\"tsPdfMetaValue\" id=\"tsCablePdfDate\">-<\/div>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"tsPdfBrand\">\r\n        <img decoding=\"async\" id=\"tsCablePdfBrandLogo\" class=\"tsPdfBrandImg\"\r\n  data-logo-url=\"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png.webp\"\r\n  src=\"https:\/\/ferroamp.com\/wp-content\/uploads\/2024\/04\/logo-black-1.png.webp\"\r\n  alt=\"Ferroamp\"\r\n  crossorigin=\"anonymous\"\r\n  style=\"height:28px; width:auto; display:block;\"\r\n>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- SECTION: Kabel (en sida) -->\r\n    <div class=\"tsPdfSection\" id=\"cablePdfSectionCore\">\r\n      <div class=\"tsPdfSectionTitle\">Cable calculation<\/div>\r\n\r\n      <div class=\"tsPdfGrid2Cards\">\r\n\r\n        <!-- V\u00c4NSTER: Ber\u00e4kningsdata -->\r\n        <div class=\"tsPdfCard\">\r\n          <div class=\"tsPdfCardTitle\">Calculation data<\/div>\r\n\r\n          <!-- Kabel A -->\r\n          <div class=\"tsPdfSubTitleRow\" id=\"tsCablePdfInputsTitleA\">\r\n            <div class=\"tsPdfSubTitle\" id=\"tsCablePdfLabelInputsA\">Cable A<\/div>\r\n            <div class=\"tsPdfSubTitleValue\" id=\"tsCablePdfCalcModeA\">-<\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfLineCompact\">\r\n            <div class=\"tsPdfLabel\">Power, lenght, max voltage drop<\/div>\r\n            <div class=\"tsPdfValue\" id=\"tsCablePdfCalcElmA\">-<\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfLineCompact\">\r\n            <div class=\"tsPdfLabel\">Temperature, insulation<\/div>\r\n            <div class=\"tsPdfValue\" id=\"tsCablePdfCalcTempA\">-<\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfLineCompact\">\r\n            <div class=\"tsPdfLabel\">Installation method<\/div>\r\n            <div class=\"tsPdfValue\" id=\"tsCablePdfCalcInstallA\">-<\/div>\r\n          <\/div>\r\n\r\n          <!-- Kabel B (valfri) -->\r\n          <div id=\"tsCablePdfCalcBlockB\" style=\"display:none;margin-top:10px;\">\r\n            <div class=\"tsPdfSubTitleRow\" id=\"tsCablePdfInputsTitleB\">\r\n              <div class=\"tsPdfSubTitle\" id=\"tsCablePdfLabelInputsB\">Cable B<\/div>\r\n              <div class=\"tsPdfSubTitleValue\" id=\"tsCablePdfCalcModeB\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfLineCompact\">\r\n              <div class=\"tsPdfLabel\">Power, lenght, max voltage drop<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfCalcElmB\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfLineCompact\">\r\n              <div class=\"tsPdfLabel\">Temperature, insulation<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfCalcTempB\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfLineCompact\">\r\n              <div class=\"tsPdfLabel\">Installation method<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfCalcInstallB\">-<\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n        <!-- H\u00d6GER: Kabelresultat -->\r\n        <div class=\"tsPdfCard\">\r\n          <div class=\"tsPdfCardTitle\">Cable result<\/div>\r\n\r\n          <div class=\"tsPdfLineGroup\" id=\"tsCablePdfGroupA\">\r\n            <div class=\"tsPdfLine\">\r\n              <div class=\"tsPdfLabel\" id=\"tsCablePdfLabelResA\">Cable A<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfResCableA\">-<\/div>\r\n            <\/div>\r\n            <div class=\"tsPdfLine tsPdfLineSub\">\r\n              <div class=\"tsPdfLabel\">Conductor configuration<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfResCondA\">-<\/div>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfDivider\" id=\"tsCablePdfDividerA\"><\/div>\r\n\r\n          <div class=\"tsPdfLineGroup\" id=\"tsCablePdfResBlockB\" style=\"display:none;\">\r\n            <div class=\"tsPdfLine\">\r\n              <div class=\"tsPdfLabel\" id=\"tsCablePdfLabelResB\">Cable B<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfResCableB\">-<\/div>\r\n            <\/div>\r\n            <div class=\"tsPdfLine tsPdfLineSub\">\r\n              <div class=\"tsPdfLabel\">Conductor configuration<\/div>\r\n              <div class=\"tsPdfValue\" id=\"tsCablePdfResCondB\">-<\/div>\r\n            <\/div>\r\n\r\n            <div class=\"tsPdfDivider\"><\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfLine\" id=\"tsCablePdfLineDrop\">\r\n            <div class=\"tsPdfLabel\">Voltage drop<\/div>\r\n            <div class=\"tsPdfValue\" id=\"tsCablePdfResDrop\">-<\/div>\r\n          <\/div>\r\n\r\n          <div class=\"tsPdfLine\" id=\"tsCablePdfLineSystemVoltage\">\r\n            <div class=\"tsPdfLabel\">System voltage<\/div>\r\n            <div class=\"tsPdfValue\">DC 760 V<\/div>\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- SECTION: Notes -->\r\n<div class=\"tsPdfSection\" id=\"cablePdfSectionNotes\">\r\n  <div class=\"tsPdfNoteBox\" id=\"tsCablePdfNoteBox\">\r\n    <div class=\"tsPdfNoteTitle\">Please note<\/div>\r\n    <ul class=\"tsPdfNoteList\" id=\"tsCablePdfNoteList\">\r\n      <li>The result is based on entered values and standardized assumptions; local conditions may affect the outcome.<\/li>\r\n      <li>Cable calculations are based on SS 436 40 00 and IEC 60364-5-52, with additional references to IEC 60228 and IEC 60269.<\/li>\r\n      <li>Dimensioning and component selection must always be verified against applicable standards and manufacturer instructions.<\/li>\r\n\r\n    <\/ul>\r\n  <\/div>\r\n<\/div>\r\n\r\n  <\/div>\r\n<\/section>\r\n\r\n<!-- Offscreen host f\u00f6r PDF rendering -->\r\n<div id=\"tsCablePdfHost\"\r\n     style=\"position:fixed; left:-10000px; top:0; width:794px; background:#fff; pointer-events:none; z-index:2147483647; opacity:1;\">\r\n<\/div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n      <\/div>\r\n    <\/section>\r\n  <\/div>\r\n<\/section>\r\n\r\n\r\n\r\n<style>\r\n\/* Tokens och utilities som kabeldelen anv\u00e4nder *\/\r\n:root{\r\n  --fa-green:#7fb52f;\r\n  --fa-green-dark:#9dc847;\r\n  --fa-border:#7fb52f;\r\n  --ts-text:#111;\r\n  --ts-muted:#666;\r\n  --ts-radius:14px;\r\n  --ts-pad:18px;\r\n  --field-radius:10px;\r\n  --label-gap:10px;\r\n  --field-min-h:46px;\r\n  --sys-gap:18px;\r\n}\r\n\r\n.ts-hidden{ display:none !important; }\r\n\r\n\/* Toggle switch (anv\u00e4nds b\u00e5de f\u00f6r \"L\u00e4gg till kablage\" och \"serie\") *\/\r\n.ts-toggle-block{ padding:10px 0; }\r\n.ts-toggle-head{ display:flex; align-items:center; gap:12px; }\r\n.ts-toggle-label{ font-weight:700; color:var(--ts-text); line-height:1.2; }\r\n\r\n.ts-switch{\r\n  position:relative;\r\n  width:38px;\r\n  height:20px;\r\n  flex:0 0 auto;\r\n}\r\n.ts-switch input{\r\n  position:absolute;\r\n  inset:0;\r\n  width:100%;\r\n  height:100%;\r\n  opacity:0;\r\n  margin:0;\r\n  cursor:pointer;\r\n}\r\n.ts-slider{\r\n  position:absolute;\r\n  inset:0;\r\n  background:#d9d9d9;\r\n  transition:0.18s;\r\n  border-radius:999px;\r\n  pointer-events:none;\r\n}\r\n.ts-slider:before{\r\n  content:\"\";\r\n  position:absolute;\r\n  height:14px;\r\n  width:14px;\r\n  left:3px;\r\n  top:3px;\r\n  background:#fff;\r\n  transition:0.18s;\r\n  border-radius:50%;\r\n  box-shadow:0 1px 2px rgba(0,0,0,0.20);\r\n}\r\n.ts-switch input:checked + .ts-slider{ background:var(--fa-green); }\r\n.ts-switch input:checked + .ts-slider:before{ transform:translateX(18px); }\r\n\r\n\/* Cards och sektioner runt kabeldelen *\/\r\n.ts-section{\r\n  width:100%;\r\n  box-sizing:border-box;\r\n  margin-top:18px;\r\n}\r\n.ts-card{\r\n  border:1px solid rgba(0,0,0,0.10);\r\n  border-radius:var(--ts-radius);\r\n  padding:var(--ts-pad);\r\n  background:#fff;\r\n  box-sizing:border-box;\r\n}\r\n\r\n\/* Inputs och labels i kabelvyn *\/\r\n#kabelkalkylatorPrint .sso-input{\r\n  border-radius:var(--field-radius) !important;\r\n  min-height:var(--field-min-h) !important;\r\n  padding:12px 14px !important;\r\n  box-sizing:border-box !important;\r\n  font-size:16px !important;\r\n  line-height:normal !important;\r\n}\r\n\r\n#kabelkalkylatorPrint label.sso-label{\r\n  display:block !important;\r\n  margin:0 0 var(--label-gap) 0 !important;\r\n  line-height:1.2 !important;\r\n}\r\n\r\n#kabelkalkylatorPrint .sso-label{\r\n  margin-bottom: 10px;      \r\n}\r\n\r\n\r\n\/* Grid och enheter *\/\r\n#kabelkalkylatorPrint .sso-grid-3{\r\n  display:grid;\r\n  grid-template-columns:repeat(3, 1fr);\r\n  gap:12px 16px;\r\n  row-gap:16px !important;\r\n}\r\n@media (max-width:720px){\r\n  #kabelkalkylatorPrint .sso-grid-3{\r\n    grid-template-columns:1fr;\r\n    gap:12px;\r\n  }\r\n}\r\n\r\n\r\n\/* Kabelkalkylator: fixa input + enhet p\u00e5 mobil *\/\r\n#kabelkalkylatorPrint .sso-unit{\r\n  display:flex !important;\r\n  align-items:center !important;\r\n  gap:10px;\r\n  width:100%;\r\n  min-width:0;\r\n}\r\n\r\n#kabelkalkylatorPrint .sso-unit .sso-input{\r\n  flex:1 1 auto !important;\r\n  min-width:0 !important;\r\n}\r\n\r\n#kabelkalkylatorPrint .sso-unit-text{\r\n  flex:0 0 auto !important;\r\n  white-space:nowrap;\r\n}\r\n\r\n\r\n\r\n\r\n#kabelkalkylatorPrint .sso-input-unit{\r\n  flex:1 1 auto;\r\n  text-align:right;\r\n}\r\n\r\n\r\n#kabelkalkylatorPrint .sso-section-title{\r\n  font-size:16px;\r\n  font-weight:700;\r\n  margin:14px 0 10px 0;\r\n  color:var(--ts-text);\r\n}\r\n\r\n\/* Mode-knappar *\/\r\n#kabelkalkylatorPrint .cc-mode-switch{\r\n  display:flex;\r\n  gap:10px;\r\n  flex-wrap:wrap;\r\n  margin:0 0 10px 0;\r\n  padding:0;\r\n  background:transparent;\r\n  border:0;\r\n}\r\n#kabelkalkylatorPrint .cc-mode-btn{\r\n  appearance:none;\r\n  -webkit-appearance:none;\r\n  border:1px solid var(--fa-border);\r\n  border-radius:6px;\r\n  padding:10px 16px;\r\n  font-size:14px;\r\n  line-height:1.1;\r\n  font-weight:700;\r\n  cursor:pointer;\r\n  background:#fff;\r\n  color:var(--ts-text);\r\n  box-sizing:border-box;\r\n  white-space:nowrap;\r\n  box-shadow:0 1px 0 rgba(0,0,0,.08);\r\n  transition:background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease, transform 80ms ease;\r\n}\r\n#kabelkalkylatorPrint .cc-mode-btn:hover{\r\n  border-color:var(--fa-green-dark);\r\n  box-shadow:0 2px 0 rgba(0,0,0,.10);\r\n}\r\n#kabelkalkylatorPrint .cc-mode-btn.is-active,\r\n#kabelkalkylatorPrint .cc-mode-btn[aria-pressed=\"true\"]{\r\n  background:var(--fa-green) !important;\r\n  border-color:var(--fa-green) !important;\r\n  color:#fff !important;\r\n}\r\n#kabelkalkylatorPrint .cc-mode-btn:active{\r\n  transform:translateY(1px);\r\n  box-shadow:0 1px 0 rgba(0,0,0,.08);\r\n}\r\n\r\n\/* Dolda radio *\/\r\n#kabelkalkylatorPrint input[type=\"radio\"][name=\"calc_mode\"],\r\n#kabelkalkylatorPrint .cc-hidden-radio{\r\n  position:absolute !important;\r\n  opacity:0 !important;\r\n  pointer-events:none !important;\r\n  width:1px !important;\r\n  height:1px !important;\r\n  margin:0 !important;\r\n}\r\n\r\n\/* Dokumentation: PDF knapp styling *\/\r\n#tsCreatePdfBtn.cc-submit{\r\n  background:var(--fa-green-dark) !important;\r\n  color:#000 !important;\r\n  border:0 !important;\r\n  border-radius:var(--field-radius) !important;\r\n  padding:12px 22px !important;\r\n  font-weight:600 !important;\r\n}\r\n\r\n\r\n\r\n#toolSuiteChooser #viewCable .cc-submit{\r\n  appearance:none !important;\r\n  -webkit-appearance:none !important;\r\n  border:1px solid var(--fa-border) !important;\r\n  border-radius:6px !important;\r\n  padding:10px 16px !important;\r\n  font-size:14px !important;\r\n  line-height:1.1 !important;\r\n  cursor:pointer !important;\r\n  font-weight:700 !important;\r\n  box-sizing:border-box !important;\r\n  background:var(--fa-green) !important;\r\n  border-color:var(--fa-green) !important;\r\n  color:#fff !important;\r\n  box-shadow:0 1px 0 rgba(0,0,0,.08) !important;\r\n  transition:background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease, transform 80ms ease !important;\r\n  white-space:nowrap !important;\r\n}\r\n#toolSuiteChooser #viewCable .cc-submit:hover{\r\n  background:var(--fa-green-dark) !important;\r\n  border-color:var(--fa-green-dark) !important;\r\n  box-shadow:0 2px 0 rgba(0,0,0,.10) !important;\r\n}\r\n#toolSuiteChooser #viewCable .cc-submit:active{\r\n  transform:translateY(1px) !important;\r\n  box-shadow:0 1px 0 rgba(0,0,0,.08) !important;\r\n}\r\n\r\n\r\n\/* Dokumentation sektion i vyn *\/\r\n#kabelkalkylatorPrint #tsCableDocSection{\r\n  margin-top:16px;\r\n}\r\n\r\n\/* Matcha systemkalkens knapprad spacing *\/\r\n#kabelkalkylatorPrint #tsCableDocSection .cc-actions{\r\n  display:flex;\r\n  justify-content:flex-start;\r\n}\r\n\r\n.sso-notes {\r\n  margin-top: 14px;\r\n  color: #8a8a8a;\r\n  font-size: 13px;\r\n  line-height: 1.45;\r\n}\r\n\r\n.sso-notes-title {\r\n  font-weight: 600;\r\n  color: #7a7a7a;\r\n  margin-bottom: 6px;\r\n}\r\n\r\n.sso-notes-list {\r\n  margin: 0;\r\n  padding-left: 16px;\r\n}\r\n\r\n.sso-notes-list li {\r\n  margin: 2px 0;\r\n}\r\n\r\n\r\n\r\n\r\n\/* =========================\r\nPDF styles: Kabel (systemk\u00e4nsla)\r\nScoped till tsCablePdfTemplate + tsCablePdfHost\r\n========================= *\/\r\n\r\n#tsCablePdfTemplate{\r\n  position:fixed !important;\r\n  left:-10000px !important;\r\n  top:0 !important;\r\n  width:794px !important;\r\n  max-width:794px !important;\r\n  visibility:hidden !important;\r\n  pointer-events:none !important;\r\n}\r\n\r\n#tsCablePdfHost{\r\n  width:794px !important;\r\n  max-width:794px !important;\r\n  overflow:hidden !important;\r\n  background:#fff !important;\r\n}\r\n\r\n#tsCablePdfHost #tsCablePdfTemplate{\r\n  display:block !important;\r\n  position:static !important;\r\n  left:auto !important;\r\n  top:auto !important;\r\n  width:794px !important;\r\n  max-width:794px !important;\r\n  visibility:visible !important;\r\n  pointer-events:none !important;\r\n}\r\n\r\n\/* Page *\/\r\n#tsCablePdfTemplate .tsPdfPage,\r\n#tsCablePdfHost .tsPdfPage{\r\n  width:794px !important;\r\n  max-width:794px !important;\r\n  box-sizing:border-box !important;\r\n  padding:48px 56px !important;\r\n  background:#fff !important;\r\n  font-family:inherit !important;\r\n  color:#111 !important;\r\n  overflow:hidden !important;\r\n}\r\n\r\n\/* Header *\/\r\n#tsCablePdfTemplate .tsPdfHeader,\r\n#tsCablePdfHost .tsPdfHeader{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  align-items:flex-start;\r\n  gap:24px;\r\n  margin-bottom:22px;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfTitle,\r\n#tsCablePdfHost .tsPdfTitle{\r\n  font-size:26px;\r\n  font-weight:700;\r\n  line-height:1.15;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfMeta,\r\n#tsCablePdfHost .tsPdfMeta{\r\n  margin-top:10px;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfMetaRow,\r\n#tsCablePdfHost .tsPdfMetaRow{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  gap:12px;\r\n  font-size:12px;\r\n  color:#666;\r\n  padding:3px 0;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfMetaLabel,\r\n#tsCablePdfHost .tsPdfMetaLabel{\r\n  font-weight:400;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfMetaValue,\r\n#tsCablePdfHost .tsPdfMetaValue{\r\n  font-weight:600;\r\n  color:#111;\r\n  white-space:nowrap;\r\n}\r\n\r\n\/* Brand *\/\r\n#tsCablePdfTemplate .tsPdfBrand,\r\n#tsCablePdfHost .tsPdfBrand{\r\n  display:flex;\r\n  justify-content:flex-end;\r\n  align-items:flex-start;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfBrandImg,\r\n#tsCablePdfHost .tsPdfBrandImg{\r\n  height:28px;\r\n  width:auto;\r\n  max-width:160px;\r\n  object-fit:contain;\r\n  display:block;\r\n}\r\n\r\n\/* Sections *\/\r\n#tsCablePdfTemplate .tsPdfSection,\r\n#tsCablePdfHost .tsPdfSection{\r\n  margin-top:16px;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfSectionTitle,\r\n#tsCablePdfHost .tsPdfSectionTitle{\r\n  font-size:14px;\r\n  font-weight:700;\r\n  margin:0 0 10px 0;\r\n}\r\n\r\n\/* 2-card grid *\/\r\n#tsCablePdfTemplate .tsPdfGrid2Cards,\r\n#tsCablePdfHost .tsPdfGrid2Cards{\r\n  display:grid;\r\n  grid-template-columns: 1fr 1fr;\r\n  column-gap:16px;\r\n  row-gap:22px;\r\n  width:100% !important;\r\n  max-width:100% !important;\r\n}\r\n\r\n\/* Cards *\/\r\n#tsCablePdfTemplate .tsPdfCard,\r\n#tsCablePdfHost .tsPdfCard{\r\n  border:1px solid #ededed;\r\n  border-radius:14px;\r\n  padding:12px 14px;\r\n  background:#fff;\r\n  min-width:0 !important;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfCardTitle,\r\n#tsCablePdfHost .tsPdfCardTitle{\r\n  font-size:14px;\r\n  font-weight:700;\r\n  margin:0 0 10px 0;\r\n}\r\n\r\n\/* Lines *\/\r\n#tsCablePdfTemplate .tsPdfLine,\r\n#tsCablePdfHost .tsPdfLine{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  gap:16px;\r\n  padding:7px 0;\r\n  border-bottom:1px solid #ededed;\r\n  box-sizing:border-box;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLine:last-child,\r\n#tsCablePdfHost .tsPdfLine:last-child{\r\n  border-bottom:0;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLabel,\r\n#tsCablePdfHost .tsPdfLabel{\r\n  font-size:12.5px;\r\n  font-weight:400;\r\n  color:#111;\r\n  min-width:0;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfValue,\r\n#tsCablePdfHost .tsPdfValue{\r\n  font-size:12.5px;\r\n  font-weight:600;\r\n  color:#111;\r\n  white-space:nowrap;\r\n  text-align:right;\r\n  min-width:0 !important;\r\n  overflow-wrap:anywhere;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfDivider,\r\n#tsCablePdfHost .tsPdfDivider{\r\n  height:1px;\r\n  background:#ededed;\r\n  margin:10px 0;\r\n}\r\n\r\n\/* Compact rows (left card) *\/\r\n#tsCablePdfTemplate .tsPdfLineCompact,\r\n#tsCablePdfHost .tsPdfLineCompact{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  gap:16px;\r\n  padding:7px 0;\r\n  border-bottom:1px solid #ededed;\r\n  box-sizing:border-box;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLineCompact:last-child,\r\n#tsCablePdfHost .tsPdfLineCompact:last-child{\r\n  border-bottom:0;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLineCompact .tsPdfValue,\r\n#tsCablePdfHost .tsPdfLineCompact .tsPdfValue{\r\n  white-space:normal;\r\n  max-width:360px;\r\n  overflow-wrap:anywhere;\r\n}\r\n\r\n\/* SubTitle row (Cable A\/B) *\/\r\n#tsCablePdfTemplate .tsPdfSubTitleRow,\r\n#tsCablePdfHost .tsPdfSubTitleRow{\r\n  display:flex;\r\n  align-items:flex-start;\r\n  justify-content:space-between;\r\n  gap:16px;\r\n  padding:7px 0;\r\n  border-bottom:1px solid #ededed;\r\n  margin:0 0 0 0;\r\n  box-sizing:border-box;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfSubTitle,\r\n#tsCablePdfHost .tsPdfSubTitle{\r\n  margin:0;\r\n  font-size:12.5px;\r\n  font-weight:400;\r\n  opacity:0.85;\r\n  line-height:1.25;\r\n  flex:1 1 auto;\r\n  min-width:0;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfSubTitleValue,\r\n#tsCablePdfHost .tsPdfSubTitleValue{\r\n  margin:0;\r\n  font-size:12.5px;\r\n  font-weight:600;\r\n  text-align:right;\r\n  line-height:1.25;\r\n  white-space:nowrap;\r\n  flex:0 0 auto;\r\n}\r\n\r\n\/* Result groups + subline *\/\r\n#tsCablePdfTemplate .tsPdfLineGroup,\r\n#tsCablePdfHost .tsPdfLineGroup{\r\n  margin-bottom:8px;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLineSub .tsPdfLabel,\r\n#tsCablePdfHost .tsPdfLineSub .tsPdfLabel{\r\n  font-size:12px;\r\n  opacity:0.8;\r\n}\r\n\r\n#tsCablePdfTemplate .tsPdfLineSub .tsPdfValue,\r\n#tsCablePdfHost .tsPdfLineSub .tsPdfValue{\r\n  font-size:12px;\r\n  font-weight:500;\r\n  opacity:0.9;\r\n  white-space:normal;\r\n  max-width:360px;\r\n  overflow-wrap:anywhere;\r\n}\r\n\r\n\/* Notes *\/\r\n#tsCablePdfTemplate .tsPdfNote,\r\n#tsCablePdfHost .tsPdfNote{\r\n  margin-top:0;\r\n  font-size:12px;\r\n  color:#666;\r\n}\r\n\r\n#kabelkalkylatorPrint .cc-alert{\r\n  margin-top:12px;\r\n  padding:12px 14px;\r\n  border-radius:10px;\r\n  border:1px solid rgba(0,0,0,0.10);\r\n  font-size:14px;\r\n  line-height:1.35;\r\n  background:#fff3cd;\r\n  border-color:#f1c36d;\r\n  color:#2b2b2b;\r\n}\r\n\r\n#kabelkalkylatorPrint .cc-alert.ts-hidden{\r\n  display:none !important;\r\n}\r\n\r\n\/* =========================================================\r\n   Kabel PDF: Nedtonad notis, utan bakgrund\r\n   Scoped till tsCablePdfHost + tsCablePdfTemplate\r\n========================================================= *\/\r\n#tsCablePdfHost .tsPdfNoteBox,\r\n#tsCablePdfTemplate .tsPdfNoteBox{\r\n  margin-top: 36px;\r\n  padding: 0;\r\n  background: transparent;\r\n\r\n  color: rgba(0,0,0,0.55);\r\n  font-size: 11.5px;\r\n  line-height: 1.35;\r\n}\r\n\r\n#tsCablePdfHost .tsPdfNoteTitle,\r\n#tsCablePdfTemplate .tsPdfNoteTitle{\r\n  font-weight: 600;\r\n  color: rgba(0,0,0,0.70);\r\n  font-size: 12px;\r\n  margin: 0 0 4px 0;\r\n}\r\n\r\n#tsCablePdfHost .tsPdfNoteList,\r\n#tsCablePdfTemplate .tsPdfNoteList{\r\n  margin: 0;\r\n  padding-left: 14px;\r\n}\r\n\r\n#tsCablePdfHost .tsPdfNoteList li,\r\n#tsCablePdfTemplate .tsPdfNoteList li{\r\n  margin: 1px 0;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\/* Nolla tema\/Elementor-styling p\u00e5 v\u00e5ra switchar *\/\r\n#toolSuiteChooser #viewCable .ts-switch input[type=\"checkbox\"] {\r\n  appearance: none !important;\r\n  -webkit-appearance: none !important;\r\n  -moz-appearance: none !important;\r\n  opacity: 0 !important;          \/* osynlig native-checkbox *\/\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n}\r\n\r\n\/* Ta bort ev. globala pseudoelement p\u00e5 span:et *\/\r\n#toolSuiteChooser #viewCable .ts-switch input[type=\"checkbox\"] + .ts-slider,\r\n#toolSuiteChooser #viewCable .ts-switch input[type=\"checkbox\"] + .ts-slider::before,\r\n#toolSuiteChooser #viewCable .ts-switch input[type=\"checkbox\"] + .ts-slider::after {\r\n  border: 0 !important;\r\n  box-shadow: none !important;\r\n}\r\n\r\n\/* \u00c5terst\u00e4ll v\u00e5r design (om n\u00e5got skrivits \u00f6ver) *\/\r\n#toolSuiteChooser #viewCable .ts-switch .ts-slider {\r\n  position:absolute;\r\n  inset:0;\r\n  background:#d9d9d9;\r\n  transition:0.18s;\r\n  border-radius:999px;\r\n}\r\n\r\n#toolSuiteChooser #viewCable .ts-switch .ts-slider::before {\r\n  content:\"\";\r\n  position:absolute;\r\n  height:14px;\r\n  width:14px;\r\n  left:3px;\r\n  top:3px;\r\n  background:#fff;\r\n  transition:0.18s;\r\n  border-radius:50%;\r\n  box-shadow:0 1px 2px rgba(0,0,0,0.20);\r\n}\r\n\r\n#toolSuiteChooser #viewCable .ts-switch input:checked + .ts-slider {\r\n  background: var(--fa-green);\r\n}\r\n\r\n#toolSuiteChooser #viewCable .ts-switch input:checked + .ts-slider::before {\r\n  transform: translateX(18px);\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<\/style>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5947ec2 elementor-widget elementor-widget-html\" data-id=\"5947ec2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\r\n\/* =========================================================\r\n   Kabelkalkylator + Dokumentation + PDF\r\n   St\u00f6d f\u00f6r flera instanser av #kabelkalkylatorPrint p\u00e5 samma sida\r\n========================================================= *\/\r\n(function () {\r\n  \"use strict\";\r\n\r\n  var SYSTEM_VOLTAGE = 760;\r\n\r\nvar conductorConfigs = {\r\n  \"3-wire\": { parallelPaths:false, name:\"3 conductors\", desc:\"L+, L-, PE\" },\r\n  \"4-wire\": { parallelPaths:false, name:\"4 conductors\", desc:\"L+, L-, X, PE\" },\r\n  \"4-wire-shielded\": { parallelPaths:true, name:\"4 conductors with shield\", desc:\"2xL+, 2xL-, PE = shield\" },\r\n  \"5-wire\": { parallelPaths:true, name:\"5 conductors\", desc:\"2xL+, 2xL-, PE\" }\r\n};\r\n\r\nfunction mapConductor(value) {\r\n  var map = { \"3\":\"3-wire\", \"4\":\"4-wire\", \"4_shield\":\"4-wire-shielded\", \"5\":\"5-wire\" };\r\n  return map[value] || \"3-wire\";\r\n}\r\n\r\nfunction conductorLabel(conductorType) {\r\n  var cfg = conductorConfigs[conductorType] || conductorConfigs[\"3-wire\"];\r\n  var a = String(cfg.name || \"\").trim();\r\n  var b = String(cfg.desc || \"\").trim();\r\n  if (a && b) return a + \" (\" + b + \")\";\r\n  return a || b || \"\";\r\n}\r\n\r\nfunction insulationLabel(v){\r\n  if (v === \"XLPE90\") return \"XLPE 90 \u00b0C\";\r\n  return \"PVC 70 \u00b0C\";\r\n}\r\n\r\n\r\n\r\n  function getAllCableRoots() {\r\n    return Array.prototype.slice.call(document.querySelectorAll(\"#kabelkalkylatorPrint\"));\r\n  }\r\n\r\n\r\n\r\n\r\n  function toNumber(v) {\r\n    if (v === null || v === undefined) return NaN;\r\n    var s = String(v).trim().replace(\",\", \".\");\r\n    var n = parseFloat(s);\r\n    return isFinite(n) ? n : NaN;\r\n  }\r\n\r\n  function formatNumber(n, decimals) {\r\n    if (!isFinite(n)) return \"-\";\r\n    return n.toLocaleString(\"sv-SE\", {\r\n      minimumFractionDigits: decimals,\r\n      maximumFractionDigits: decimals\r\n    });\r\n  }\r\n\r\n  function initCableCalculatorForRoot(root) {\r\n    if (!root) return;\r\n    if (root.dataset.ccInitialized === \"1\") return;\r\n\r\n    if (!root.querySelector(\"#ccCalcBtn\") || !root.querySelector(\"#ccResultWrap\")) return;\r\n\r\n    root.dataset.ccInitialized = \"1\";\r\n\r\n    function q(id) { return root.querySelector(\"#\" + id); }\r\n    \r\n    function getCableName(which) {\r\n  var id = (which === \"A\") ? \"tsCableNameA\" : \"tsCableNameB\";\r\n  var el = q(id);\r\n  var name = el ? String(el.value || \"\").trim() : \"\";\r\n  return name;\r\n}\r\n\r\nfunction cableDisplayLabel(which) {\r\n  var name = getCableName(which);\r\n  return name ? name : (\"Cable \" + which);\r\n}\r\n\r\n\r\nfunction showCalcAlert(msg){\r\n  var el = q(\"ccCalcAlert\");\r\n  if (!el) return;\r\n  el.textContent = String(msg || \"\");\r\n  el.style.display = \"\";\r\n}\r\n\r\nfunction hideCalcAlert(){\r\n  var el = q(\"ccCalcAlert\");\r\n  if (!el) return;\r\n  el.textContent = \"\";\r\n  el.style.display = \"none\";\r\n}\r\n\r\n\r\n\r\n\r\n    function setHidden(el, hidden) {\r\n      if (!el) return;\r\n      el.classList.toggle(\"ts-hidden\", !!hidden);\r\n    }\r\n\r\n    function showEl(el) { if (el) el.style.display = \"\"; }\r\n    function hideEl(el) { if (el) el.style.display = \"none\"; }\r\n\r\n    function setText(id, txt) {\r\n      var el = q(id);\r\n      if (!el) return;\r\n      el.textContent = (txt == null || txt === \"\") ? \"-\" : String(txt);\r\n    }\r\n\r\n    function setButtonActive(btn, active) {\r\n      if (!btn) return;\r\n      btn.classList.toggle(\"is-active\", !!active);\r\n      btn.setAttribute(\"aria-pressed\", active ? \"true\" : \"false\");\r\n    }\r\n\r\n    function isInsideDocSection(el) {\r\n      if (!el || !el.closest) return false;\r\n      return !!el.closest(\"#tsCableDocSection\");\r\n    }\r\n\r\n    function getMode() {\r\n      var checked = root.querySelector('input[name=\"calc_mode\"]:checked');\r\n      return (checked && checked.value) ? checked.value : \"fromLoad\";\r\n    }\r\n\r\nfunction setMode(mode) {\r\n  var radioLoad = q(\"modeFromLoad\");\r\n  var radioCable = q(\"modeFromCable\");\r\n\r\n  if (radioLoad) radioLoad.checked = (mode === \"fromLoad\");\r\n  if (radioCable) radioCable.checked = (mode === \"fromCable\");\r\n\r\n  setButtonActive(q(\"modeBtnFromLoad\"), mode === \"fromLoad\");\r\n  setButtonActive(q(\"modeBtnFromCable\"), mode === \"fromCable\");\r\n\r\n  var knownFields = q(\"knownCableFieldsA\");\r\n  var powerField = q(\"powerFieldA\");\r\n  if (knownFields) knownFields.style.display = (mode === \"fromCable\") ? \"\" : \"none\";\r\n  if (powerField) powerField.style.display = (mode === \"fromCable\") ? \"none\" : \"\";\r\n\r\n  enforceSeriesAvailabilityByMode();\r\n  invalidateCableCalculation();\r\n}\r\n    function normalizePercentString(v){\r\n  return String(v == null ? \"\" : v).trim().replace(\",\", \".\");\r\n}\r\n\r\nfunction maybeAutoSetDropAForSeries(){\r\n  \/\/ Regel:\r\n  \/\/ N\u00e4r serie sl\u00e5s p\u00e5: \u00e4ndra maxDrop (A) fr\u00e5n 1% till 0,5%\r\n  \/\/ men bara om anv\u00e4ndaren inte redan \u00e4ndrat bort fr\u00e5n 1.\r\n  var a = q(\"maxDrop\");\r\n  if (!a) return;\r\n\r\n  \/\/ S\u00e4tt bara n\u00e4r serie \u00e4r aktiv\r\n  if (!isSeriesOn()) return;\r\n\r\n  var curr = normalizePercentString(a.value);\r\n\r\n  \/\/ Acceptera \"1\", \"1.0\", \"1.00\", \"1,0\", osv som \"1\"\r\n  var currNum = parseFloat(curr);\r\n  if (!isFinite(currNum)) return;\r\n\r\n  \/\/ Byt bara om det i praktiken \u00e4r 1.0\r\n  if (Math.abs(currNum - 1.0) < 1e-9) {\r\n    a.value = \"0.5\";\r\n  }\r\n}\r\n\r\n    function isSeriesOn() {\r\n      var t = q(\"seriesToggle\");\r\n      return !!(t && t.checked);\r\n    }\r\n\r\n    function enforceSeriesAvailabilityByMode() {\r\n      var mode = getMode();\r\n      var allowSeries = (mode === \"fromLoad\");\r\n\r\n      var seriesToggle = q(\"seriesToggle\");\r\n      var seriesInputs = q(\"seriesInputs\");\r\n      var seriesWrap = seriesToggle ? seriesToggle.closest(\".cc-series-wrap\") : null;\r\n\r\n      if (!allowSeries) {\r\n        if (seriesToggle) {\r\n          seriesToggle.checked = false;\r\n          seriesToggle.disabled = true;\r\n          seriesToggle.setAttribute(\"aria-disabled\", \"true\");\r\n        }\r\n        if (seriesInputs) seriesInputs.style.display = \"none\";\r\n        if (seriesWrap) seriesWrap.style.display = \"none\";\r\n        return;\r\n      }\r\n\r\n      if (seriesToggle) {\r\n        seriesToggle.disabled = false;\r\n        seriesToggle.setAttribute(\"aria-disabled\", \"false\");\r\n      }\r\n      if (seriesWrap) seriesWrap.style.display = \"\";\r\n      if (seriesInputs) seriesInputs.style.display = (seriesToggle && seriesToggle.checked) ? \"\" : \"none\";\r\n    }\r\n\r\n    var resistivity = { Copper: 0.0175, Aluminum: 0.0283 };\r\n    var tempCoeff = 0.004;\r\n\r\n    var installFactor = { A1:0.70, A2:0.80, B1:0.85, C:1.00, D1:0.90, D2:0.85, E:1.00 };\r\n    var insulationFactor = { PVC70:1.00, XLPE90:1.20 };\r\n    var baseCurrentDensity = { Copper:10, Aluminum:7 };\r\n\r\n    \r\n\r\n    var copperSections = [1.5, 2.5, 4, 6, 10, 16];\r\n    var aluminumSections = [16, 25, 35, 50, 70, 95, 120, 150, 185, 240];\r\n    var copperExistingSections = [1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240];\r\n    var aluminumExistingSections = aluminumSections.slice();\r\n\r\n    function currentFromPowerKw(powerKw) {\r\n      return (powerKw * 1000) \/ SYSTEM_VOLTAGE;\r\n    }\r\n\r\n    function computeVoltageDropPercent(material, crossSection, length, current, temperature, conductorType) {\r\n      var rho = resistivity[material];\r\n      var cfg = conductorConfigs[conductorType] || conductorConfigs[\"3-wire\"];\r\n\r\n      var tempCorrection = 1 + tempCoeff * (temperature - 20);\r\n      var resistancePerConductor = (rho * length \/ crossSection) * tempCorrection;\r\n      var effectiveResistance = cfg.parallelPaths ? (resistancePerConductor \/ 2) : resistancePerConductor;\r\n\r\n      var voltageDrop = 2 * current * effectiveResistance;\r\n      return (voltageDrop \/ SYSTEM_VOLTAGE) * 100;\r\n    }\r\n\r\n    function computeAllowableCurrent(material, crossSection, installMethod, insulationType) {\r\n      var baseDensity = baseCurrentDensity[material] || 8;\r\n      var kInstall = installFactor[installMethod] || 1.0;\r\n      var kInsul = insulationFactor[insulationType] || 1.0;\r\n      return (baseDensity * crossSection) * kInstall * kInsul;\r\n    }\r\n\r\n    function solveForNewCable(input) {\r\n      if (!(input.powerKw > 0 && input.lengthM > 0 && input.maxDropPct > 0)) return null;\r\n\r\n      var conductorType = input.conductorType;\r\n      var current = currentFromPowerKw(input.powerKw);\r\n\r\n      function evaluate(material, crossSection) {\r\n        var dropPct = computeVoltageDropPercent(material, crossSection, input.lengthM, current, input.temperatureC, conductorType);\r\n        var allowable = computeAllowableCurrent(material, crossSection, input.installMethod, input.insulationType);\r\n        return {\r\n          material: material,\r\n          crossSection: crossSection,\r\n          conductorType: conductorType,\r\n          currentA: current,\r\n          allowableA: allowable,\r\n          dropPct: dropPct,\r\n          okDrop: (dropPct <= input.maxDropPct),\r\n          okCurrent: (current <= allowable)\r\n        };\r\n      }\r\n\r\n      var candidates = [];\r\n      for (var i=0;i<copperSections.length;i++) candidates.push(evaluate(\"Copper\", copperSections[i]));\r\n      for (var j=0;j<aluminumSections.length;j++) candidates.push(evaluate(\"Aluminum\", aluminumSections[j]));\r\n\r\n      var valid = candidates.filter(function(c){ return c.okDrop && c.okCurrent; });\r\n      if (!valid.length) return null;\r\n\r\n      valid.sort(function(a,b){\r\n        if (a.crossSection !== b.crossSection) return a.crossSection - b.crossSection;\r\n        if (a.material !== b.material) return (a.material === \"Copper\") ? -1 : 1;\r\n        return 0;\r\n      });\r\n\r\n      return valid[0];\r\n    }\r\n\r\n    function solveForExistingCable(input) {\r\n      if (!(input.crossSection > 0 && input.lengthM > 0 && input.maxDropPct > 0)) return null;\r\n\r\n      var cfg = conductorConfigs[input.conductorType] || conductorConfigs[\"3-wire\"];\r\n      var rho = resistivity[input.material];\r\n      if (!rho) return null;\r\n\r\n      var tempCorrection = 1 + tempCoeff * (input.temperatureC - 20);\r\n      var resistancePerConductor = (rho * input.lengthM \/ input.crossSection) * tempCorrection;\r\n      var effectiveResistance = cfg.parallelPaths ? (resistancePerConductor \/ 2) : resistancePerConductor;\r\n      if (!(effectiveResistance > 0)) return null;\r\n\r\n      var allowableA = computeAllowableCurrent(input.material, input.crossSection, input.installMethod, input.insulationType);\r\n\r\n      var maxVoltDropAbs = input.maxDropPct * SYSTEM_VOLTAGE \/ 100;\r\n      var limitCurrentByDrop = maxVoltDropAbs \/ (2 * effectiveResistance);\r\n\r\n      var currentA = Math.min(allowableA, limitCurrentByDrop);\r\n      if (!(currentA > 0)) return null;\r\n\r\n      var dropPct = (2 * currentA * effectiveResistance \/ SYSTEM_VOLTAGE) * 100;\r\n      var powerKw = (currentA * SYSTEM_VOLTAGE) \/ 1000;\r\n\r\n      return {\r\n        material: input.material,\r\n        crossSection: input.crossSection,\r\n        conductorType: input.conductorType,\r\n        allowableA: allowableA,\r\n        currentA: currentA,\r\n        dropPct: dropPct,\r\n        powerKw: powerKw,\r\n        limitBy: (currentA === allowableA) ? \"ampacity\" : \"voltageDrop\"\r\n      };\r\n    }\r\n\r\n    function readNewCableInput(isB) {\r\n      var powerEl = q(isB ? \"power2\" : \"power\");\r\n      var lenEl = q(isB ? \"length2\" : \"length\");\r\n      var dropEl = q(isB ? \"maxDrop2\" : \"maxDrop\");\r\n      var tempEl = q(isB ? \"ambientTemp2\" : \"ambientTemp\");\r\n\r\n      var condEl = q(isB ? \"conductorConfigB\" : \"conductorConfigA\");\r\n      var instEl = q(isB ? \"installMethod2\" : \"installMethod\");\r\n      var insuEl = q(isB ? \"insulationType2\" : \"insulationType\");\r\n\r\n      return {\r\n        powerKw: toNumber(powerEl && powerEl.value),\r\n        lengthM: toNumber(lenEl && lenEl.value),\r\n        maxDropPct: toNumber(dropEl && dropEl.value),\r\n        temperatureC: toNumber(tempEl && tempEl.value),\r\n        installMethod: (instEl && instEl.value) ? instEl.value : \"C\",\r\n        insulationType: (insuEl && insuEl.value) ? insuEl.value : \"PVC70\",\r\n        conductorType: mapConductor(condEl ? condEl.value : \"3\")\r\n      };\r\n    }\r\n\r\n    function readExistingCableInput() {\r\n      var lenEl = q(\"length\");\r\n      var dropEl = q(\"maxDrop\");\r\n      var tempEl = q(\"ambientTemp\");\r\n\r\n      var instEl = q(\"installMethod\");\r\n      var insuEl = q(\"insulationType\");\r\n      var condEl = q(\"conductorConfigA\");\r\n      var sel = q(\"knownCableTypeA\");\r\n\r\n      var material = \"Copper\";\r\n      var crossSection = 0;\r\n\r\n      if (sel && sel.value) {\r\n        var parts = String(sel.value).split(\"_\");\r\n        if (parts.length === 2) {\r\n          material = (parts[0] === \"ALU\") ? \"Aluminum\" : \"Copper\";\r\n          crossSection = toNumber(parts[1]) || 0;\r\n        }\r\n      }\r\n\r\n      return {\r\n        material: material,\r\n        crossSection: crossSection,\r\n        lengthM: toNumber(lenEl && lenEl.value),\r\n        maxDropPct: toNumber(dropEl && dropEl.value),\r\n        temperatureC: toNumber(tempEl && tempEl.value),\r\n        installMethod: (instEl && instEl.value) ? instEl.value : \"C\",\r\n        insulationType: (insuEl && insuEl.value) ? insuEl.value : \"PVC70\",\r\n        conductorType: mapConductor(condEl ? condEl.value : \"3\")\r\n      };\r\n    }\r\n\r\n    function populateKnownCableOptions() {\r\n      var sel = q(\"knownCableTypeA\");\r\n      if (!sel) return;\r\n\r\n      var currentValue = String(sel.value || \"\");\r\n      sel.innerHTML = \"\";\r\n\r\n      var placeholder = document.createElement(\"option\");\r\n      placeholder.value = \"\";\r\n      placeholder.textContent = \"Select cable type\";\r\n      placeholder.disabled = true;\r\n      sel.appendChild(placeholder);\r\n\r\n      for (var i=0;i<copperExistingSections.length;i++){\r\n        var cs = copperExistingSections[i];\r\n        var opt = document.createElement(\"option\");\r\n        opt.value = \"CU_\" + cs;\r\n        opt.textContent = \"CU \" + cs + \" mm\u00b2\";\r\n        sel.appendChild(opt);\r\n      }\r\n      for (var j=0;j<aluminumExistingSections.length;j++){\r\n        var cs2 = aluminumExistingSections[j];\r\n        var opt2 = document.createElement(\"option\");\r\n        opt2.value = \"ALU_\" + cs2;\r\n        opt2.textContent = \"ALU \" + cs2 + \" mm\u00b2\";\r\n        sel.appendChild(opt2);\r\n      }\r\n\r\n      sel.value = currentValue || \"\";\r\n      placeholder.selected = (sel.value === \"\");\r\n    }\r\n\r\n    function hasValue(id) {\r\n      var el = q(id);\r\n      if (!el) return false;\r\n      return String(el.value || \"\").trim() !== \"\";\r\n    }\r\n\r\n    function validate(mode) {\r\n      if (mode === \"fromCable\") {\r\n        if (!hasValue(\"knownCableTypeA\")) return { ok: false, msg: \"Select conductor cross-section for the existing cable.\" };\r\n        if (!hasValue(\"length\") || !hasValue(\"maxDrop\") || !hasValue(\"ambientTemp\")) {\r\n          return { ok: false, msg: \"Enter cable length, maximum voltage drop, and ambient temperature.\" };\r\n        }\r\n        return { ok: true, msg: \"\" };\r\n      }\r\n    \r\n      if (!hasValue(\"power\") || !hasValue(\"length\") || !hasValue(\"maxDrop\") || !hasValue(\"ambientTemp\")) {\r\n        return { ok: false, msg: \"Enter power, cable length, maximum voltage drop, and ambient temperature for cable A.\" };\r\n      }\r\n    \r\n      if (isSeriesOn()) {\r\n        if (!hasValue(\"power2\") || !hasValue(\"length2\") || !hasValue(\"maxDrop2\") || !hasValue(\"ambientTemp2\")) {\r\n          return { ok: false, msg: \"Series calculation is enabled. Enter power, cable length, maximum voltage drop, and ambient temperature for cable B.\" };\r\n        }\r\n      }\r\n\r\n      return { ok:true, msg:\"\" };\r\n    }\r\n\r\n    var resultWrap = q(\"ccResultWrap\");\r\n    var lineA = q(\"ccLineA\");\r\n    var lineB = q(\"ccLineB\");\r\n    var lineTotal = q(\"ccLineTotal\");\r\n    var resultLines = root.querySelector(\".sso-result-lines\");\r\n    \r\n    function setResultVisible(visible) {\r\n      setHidden(resultWrap, !visible);\r\n    }\r\n\r\nfunction clearResult() {\r\n  setResultVisible(false);\r\n\r\n  hideEl(lineA);\r\n  hideEl(lineB);\r\n  hideEl(lineTotal);\r\n\r\n  if (resultLines) resultLines.style.display = \"none\";   \/\/ L\u00c4GG TILL\r\n\r\n  setText(\"ccResA\", \"-\");\r\n  setText(\"ccResB\", \"-\");\r\n  setText(\"ccResTotal\", \"-\");\r\n\r\n  hideCalcAlert();\r\n\r\n  setHidden(q(\"tsCableNameRowA\"), true);\r\n  setHidden(q(\"tsCableNameRowB\"), true);\r\n\r\n  root.__cableLastResult = { ok:false };\r\n  root.__cableHasCalculated = false;\r\n}\r\n    function invalidateCableCalculation() {\r\n      clearResult();\r\n    }\r\n\r\nfunction renderMessage(msg) {\r\n  setResultVisible(true);\r\n\r\n  \/\/ visa alert\r\n  showCalcAlert(msg || \"-\");\r\n\r\n  \/\/ d\u00f6lj resultatraderna helt (tar bort vita rutan)\r\n  if (resultLines) resultLines.style.display = \"none\";\r\n\r\n  \/\/ s\u00e4kerst\u00e4ll att inga rader r\u00e5kar synas\r\n  hideEl(lineA);\r\n  hideEl(lineB);\r\n  hideEl(lineTotal);\r\n\r\n  \/\/ skriv inget i ccResTotal n\u00e4r det \u00e4r varning\r\n  setText(\"ccResTotal\", \"-\");\r\n}\r\n\r\nfunction renderNewCable(resA, resB) {\r\n  setResultVisible(true);\r\n  hideCalcAlert();\r\n\r\n  if (resultLines) resultLines.style.display = \"\";\r\n\r\n      if (resA) {\r\n        showEl(lineA);\r\n        var txtA =\r\n          String(resA.crossSection).replace(\".\", \",\") + \" mm\u00b2 \" +\r\n          (resA.material === \"Copper\" ? \"copper\" : \"aluminium\") +\r\n          \", \" + conductorLabel(resA.conductorType)\r\n          ;\r\n        setText(\"ccResA\", txtA);\r\n        setHidden(q(\"tsCableNameRowA\"), false);\r\n      } else {\r\n        hideEl(lineA);\r\n        setText(\"ccResA\", \"-\");\r\n        setHidden(q(\"tsCableNameRowA\"), true);\r\n      }\r\n\r\n      if (resB) {\r\n        showEl(lineB);\r\n        var txtB =\r\n          String(resB.crossSection).replace(\".\", \",\") + \" mm\u00b2 \" +\r\n          (resB.material === \"Copper\" ? \"copper\" : \"aluminium\") +\r\n          \", \" + conductorLabel(resB.conductorType)\r\n          ;\r\n        setText(\"ccResB\", txtB);\r\n        setHidden(q(\"tsCableNameRowB\"), false);\r\n      } else {\r\n        hideEl(lineB);\r\n        setText(\"ccResB\", \"-\");\r\n        setHidden(q(\"tsCableNameRowB\"), true);\r\n      }\r\n\r\n      showEl(lineTotal);\r\n      var totalDrop = (resA ? resA.dropPct : 0) + (resB ? resB.dropPct : 0);\r\n      setText(\"ccResTotal\", totalDrop.toFixed(2).replace(\".\", \",\") + \" %\");\r\n    }\r\n\r\nfunction renderExistingCable(res) {\r\n  setResultVisible(true);\r\n  hideCalcAlert();\r\n\r\n  if (resultLines) resultLines.style.display = \"\";\r\n\r\n  showEl(lineA);\r\n  hideEl(lineB);\r\n  showEl(lineTotal);\r\n\r\n  var cableTxt =\r\n    \"Selected cable: \" +\r\n    String(res.crossSection).replace(\".\", \",\") + \" mm\u00b2 \" +\r\n    (res.material === \"Copper\" ? \"copper\" : \"aluminum\") +\r\n    \", \" + conductorLabel(res.conductorType);\r\n\r\n  setText(\"ccResA\", cableTxt);\r\n  setHidden(q(\"tsCableNameRowA\"), false);\r\n  setHidden(q(\"tsCableNameRowB\"), true);\r\n\r\n  var limitText =\r\n    (res.limitBy === \"ampacity\")\r\n      ? \"Limiting factor: current-carrying capacity.\"\r\n      : \"Limiting factor: voltage drop.\";\r\n\r\n  var totalTxt =\r\n    \"Max power \" + formatNumber(res.powerKw, 1) +\r\n    \" kW. Voltage drop \" + res.dropPct.toFixed(2).replace(\".\", \",\") +\r\n    \" %. \" + limitText;\r\n\r\n  setText(\"ccResTotal\", totalTxt);\r\n}\r\n\r\nfunction notifyCableCalculated() {\r\n  try {\r\n    root.dispatchEvent(new CustomEvent(\"ts:cableCalculated\", { bubbles: true }));\r\n  } catch (e) {\r\n    var evt = document.createEvent(\"Event\");\r\n    evt.initEvent(\"ts:cableCalculated\", true, true);\r\n    root.dispatchEvent(evt);\r\n  }\r\n}\r\n\r\nfunction calculate() {\r\n  invalidateCableCalculation();\r\n\r\n  var mode = getMode();\r\n  var validation = validate(mode);\r\n\r\n  if (!validation.ok) {\r\n    renderMessage(validation.msg);\r\n    root.__cableLastResult = { ok: false };\r\n    root.__cableHasCalculated = false;\r\n    return false;\r\n  }\r\n\r\n  if (mode === \"fromCable\") {\r\n    var invInput = readExistingCableInput();\r\n    if (!(invInput.crossSection > 0)) {\r\n      renderMessage(\"Select conductor cross-section for the existing cable.\");\r\n      root.__cableLastResult = { ok: false };\r\n      root.__cableHasCalculated = false;\r\n      return false;\r\n    }\r\n\r\n    var invRes = solveForExistingCable(invInput);\r\n    if (!invRes) {\r\n      renderMessage(\"With the given conditions, no permissible load can be calculated. Adjust cable data or maximum voltage drop.\");\r\n      root.__cableLastResult = { ok: false };\r\n      root.__cableHasCalculated = false;\r\n      return false;\r\n    }\r\n\r\n        renderExistingCable(invRes);\r\n\r\n        root.__cableLastResult = {\r\n  ok:true,\r\n  mode:\"fromCable\",\r\n  a: invRes,\r\n  b: null,\r\n  totalDropPct: invRes.dropPct,\r\n  inputA: readExistingCableInput(),\r\n  ui: {\r\n    conductorA: q(\"conductorConfigA\") ? q(\"conductorConfigA\").value : \"3\",\r\n    installA: q(\"installMethod\") ? q(\"installMethod\").value : \"C\",\r\n    insulationA: q(\"insulationType\") ? q(\"insulationType\").value : \"PVC70\"\r\n  }\r\n};\r\n        root.__cableHasCalculated = true;\r\n\r\n        notifyCableCalculated();\r\n        return true;\r\n      }\r\n\r\n      var inputA = readNewCableInput(false);\r\n      var resA = solveForNewCable(inputA);\r\n\r\n    if (!resA) {\r\n      renderMessage(\"The calculator supports aluminum cables up to 240 mm\u00b2. For projects requiring larger cross-sections, engineering-based design is recommended.\");\r\n      root.__cableLastResult = { ok: false };\r\n      root.__cableHasCalculated = false;\r\n      return false;\r\n    }\r\n    \r\n    var resB = null;\r\n    if (isSeriesOn()) {\r\n      var inputB = readNewCableInput(true);\r\n      resB = solveForNewCable(inputB);\r\n      if (!resB) {\r\n        renderMessage(\"The calculator supports aluminum cables up to 240 mm\u00b2. For projects requiring larger cross-sections, engineering-based design is recommended.\");\r\n        root.__cableLastResult = { ok: false };\r\n        root.__cableHasCalculated = false;\r\n        return false;\r\n      }\r\n    }\r\n\r\n      renderNewCable(resA, resB);\r\n\r\n      root.__cableLastResult = {\r\n  ok:true,\r\n  mode:\"fromLoad\",\r\n  a: resA,\r\n  b: resB,\r\n  totalDropPct: (resA.dropPct || 0) + (resB ? (resB.dropPct || 0) : 0),\r\n  inputA: inputA,\r\n  inputB: resB ? readNewCableInput(true) : null,\r\n  ui: {\r\n    conductorA: q(\"conductorConfigA\") ? q(\"conductorConfigA\").value : \"3\",\r\n    conductorB: q(\"conductorConfigB\") ? q(\"conductorConfigB\").value : \"3\",\r\n    installA: q(\"installMethod\") ? q(\"installMethod\").value : \"C\",\r\n    installB: q(\"installMethod2\") ? q(\"installMethod2\").value : \"C\",\r\n    insulationA: q(\"insulationType\") ? q(\"insulationType\").value : \"PVC70\",\r\n    insulationB: q(\"insulationType2\") ? q(\"insulationType2\").value : \"PVC70\"\r\n  }\r\n};\r\n      root.__cableHasCalculated = true;\r\n\r\n      notifyCableCalculated();\r\n      return true;\r\n    }\r\n\r\n    populateKnownCableOptions();\r\n\r\n    var dropA = q(\"maxDrop\");\r\n    var dropB = q(\"maxDrop2\");\r\n    if (dropA && String(dropA.value || \"\").trim() === \"\") dropA.value = \"1\";\r\n    if (dropB && String(dropB.value || \"\").trim() === \"\") dropB.value = \"0.5\";\r\n\r\n    enforceSeriesAvailabilityByMode();\r\n    setMode(\"fromLoad\");\r\n    maybeAutoSetDropAForSeries();\r\n    invalidateCableCalculation();\r\n\r\n    root.__tsCableCalc = { calculate: calculate };\r\n\r\n    root.addEventListener(\"click\", function(e){\r\n      var t = e.target;\r\n\r\n      var btnLoad = t && t.closest ? t.closest(\"#modeBtnFromLoad\") : null;\r\n      if (btnLoad) { e.preventDefault(); setMode(\"fromLoad\"); return; }\r\n\r\n      var btnCable = t && t.closest ? t.closest(\"#modeBtnFromCable\") : null;\r\n      if (btnCable) { e.preventDefault(); setMode(\"fromCable\"); return; }\r\n\r\n      var calcBtn = t && t.closest ? t.closest(\"#ccCalcBtn\") : null;\r\n      if (calcBtn) { e.preventDefault(); calculate(); return; }\r\n    }, true);\r\n\r\n    root.addEventListener(\"change\", function(e){\r\n      var el = e.target;\r\n      if (isInsideDocSection(el)) return;\r\n\r\n      if (el && el.id === \"seriesToggle\") {\r\n  enforceSeriesAvailabilityByMode();\r\n  maybeAutoSetDropAForSeries(); \r\n  invalidateCableCalculation();\r\n  return;\r\n}\r\n      if (el && (el.id === \"modeFromLoad\" || el.id === \"modeFromCable\")) { setMode(getMode()); return; }\r\n\r\n      if (el && (el.tagName === \"INPUT\" || el.tagName === \"SELECT\" || el.tagName === \"TEXTAREA\")) invalidateCableCalculation();\r\n    }, true);\r\n\r\n    root.addEventListener(\"input\", function(e){\r\n      var el = e.target;\r\n      if (isInsideDocSection(el)) return; \r\n      if (el && (el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\")) invalidateCableCalculation();\r\n   \r\n    }, true);\r\n  }\r\n\r\nfunction initCablePdfForRoot(root) {\r\n  if (!root) return;\r\n  if (root.dataset.ccPdfInitialized === \"1\") return;\r\n\r\n  var docSection = root.querySelector(\"#tsCableDocSection\");\r\n  var pdfHost = root.querySelector(\"#tsCablePdfHost\");\r\n  var pdfButton = root.querySelector(\"#tsCreatePdfBtn\");\r\n\r\n  if (!docSection || !pdfHost || !pdfButton) return;\r\n\r\n  root.dataset.ccPdfInitialized = \"1\";\r\n\r\n  function q(id){ return root.querySelector(\"#\" + id); }\r\n\r\n  function setHidden(el, hidden) {\r\n    if (!el) return;\r\n    el.classList.toggle(\"ts-hidden\", !!hidden);\r\n  }\r\n\r\n  function textValue(el){\r\n    return (el && el.value != null) ? String(el.value).trim() : \"\";\r\n  }\r\n\r\n  function nowIsoDate(){\r\n    var d = new Date();\r\n    var yyyy = d.getFullYear();\r\n    var mm = String(d.getMonth() + 1).padStart(2, \"0\");\r\n    var dd = String(d.getDate()).padStart(2, \"0\");\r\n    return yyyy + \"-\" + mm + \"-\" + dd;\r\n  }\r\n\r\n  function getLastOk(){\r\n    if (!(root.__cableHasCalculated === true)) return null;\r\n    var r = root.__cableLastResult;\r\n    if (!(r && r.ok === true)) return null;\r\n    return r;\r\n  }\r\n\r\n  function syncNameRows(lastResult){\r\n    var rowA = q(\"tsCableNameRowA\");\r\n    var rowB = q(\"tsCableNameRowB\");\r\n\r\n    if (!lastResult) {\r\n      setHidden(rowA, true);\r\n      setHidden(rowB, true);\r\n      return;\r\n    }\r\n\r\n    setHidden(rowA, false);\r\n    setHidden(rowB, !(lastResult.mode === \"fromLoad\" && lastResult.b));\r\n  }\r\n\r\n  function ensureDocVisibility(){\r\n    var lastOk = getLastOk();\r\n    setHidden(docSection, !lastOk);\r\n    syncNameRows(lastOk);\r\n  }\r\n\r\n  function setTextIn(rootEl, id, txt){\r\n    var el = rootEl.querySelector(\"#\" + id);\r\n    if (!el) return;\r\n    el.textContent = (txt == null || txt === \"\") ? \"-\" : String(txt);\r\n  }\r\n\r\n  function setVisibleIn(rootEl, id, visible){\r\n    var el = rootEl.querySelector(\"#\" + id);\r\n    if (!el) return;\r\n    el.style.display = visible ? \"\" : \"none\";\r\n  }\r\n\r\n  function resolveBrandLogoUrl(){\r\n    if (window.toolSuiteData && window.toolSuiteData.brandLogoUrl) return String(window.toolSuiteData.brandLogoUrl);\r\n    return \"\";\r\n  }\r\n\r\n\r\n\r\n\r\n\r\nfunction fillCablePdfTemplate(lastResult, tplRoot){\r\nfunction getVal(id){\r\n  var el = root.querySelector(\"#\" + id);   \/\/ l\u00e4s fr\u00e5n formul\u00e4ret i root, inte fr\u00e5n template\r\n  return el ? String(el.value || \"\") : \"\";\r\n}\r\n\r\nfunction selectText(id){\r\n  var el = root.querySelector(\"#\" + id);   \/\/ select i formul\u00e4ret\r\n  if (!el) return \"\";\r\n  if (el.tagName === \"SELECT\") {\r\n    var opt = el.options && el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null;\r\n    return opt ? String(opt.text || \"\").trim() : \"\";\r\n  }\r\n  return \"\";\r\n}\r\n\r\n  function fmtKw(v){ return formatNumber(toNumber(v), 0) + \" kW\"; }\r\n  function fmtM(v){ return formatNumber(toNumber(v), 0) + \" m\"; }\r\n  function fmtPct(v){ return formatNumber(toNumber(v), 1).replace(\".\", \",\") + \" %\"; }\r\n  function fmtTemp(v){ return formatNumber(toNumber(v), 0) + \" \u00b0C\"; }\r\n\r\n  var projectName = textValue(q(\"tsProjectName\"));\r\n  setTextIn(tplRoot, \"tsCablePdfDate\", nowIsoDate());\r\n  setTextIn(tplRoot, \"tsCablePdfMode\", lastResult.mode === \"fromCable\" ? \"Existing cable\" : \"New cable\");\r\n  setTextIn(tplRoot, \"tsCablePdfProjectName\", projectName || \"-\");\r\n  setTextIn(tplRoot, \"tsCablePdfProjectNameMini\", projectName || \"-\");\r\n\r\n  var hasB = (lastResult.mode === \"fromLoad\" && !!lastResult.b);\r\n\r\n  setVisibleIn(tplRoot, \"tsCablePdfCalcBlockB\", hasB);\r\n  setVisibleIn(tplRoot, \"tsCablePdfResBlockB\", hasB);\r\n  \r\n  var nameA = textValue(q(\"tsCableNameA\"));\r\nvar nameB = textValue(q(\"tsCableNameB\"));\r\n\r\nvar labelA = nameA ? nameA : \"Cable A\";\r\nvar labelB = nameB ? nameB : \"Cable B\";\r\n\r\nsetTextIn(tplRoot, \"tsCablePdfLabelInputsA\", labelA);\r\nsetTextIn(tplRoot, \"tsCablePdfLabelResA\", labelA);\r\n\r\n\/\/ Kabel B \u00e4r valfri i PDF, men label kan s\u00e4ttas \u00e4nd\u00e5\r\nsetTextIn(tplRoot, \"tsCablePdfLabelInputsB\", labelB);\r\nsetTextIn(tplRoot, \"tsCablePdfLabelResB\", labelB);\r\n\r\n  \/\/ =========\r\n  \/\/ Ber\u00e4kningsdata, Kabel A\r\n  \/\/ =========\r\n  setTextIn(tplRoot, \"tsCablePdfCalcModeA\", lastResult.mode === \"fromCable\" ? \"Existing cable\" : \"New cable\");\r\n\r\n  if (lastResult.mode === \"fromCable\") {\r\n    var selA = q(\"knownCableTypeA\");\r\n    var selATxt = (selA && selA.options && selA.selectedIndex >= 0)\r\n      ? String(selA.options[selA.selectedIndex].text || \"\").trim()\r\n      : \"-\";\r\n\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfCalcElmA\",\r\n      selATxt + \", \" + fmtM(getVal(\"length\")) + \", \" + fmtPct(getVal(\"maxDrop\"))\r\n    );\r\n  } else {\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfCalcElmA\",\r\n      fmtKw(getVal(\"power\")) + \", \" + fmtM(getVal(\"length\")) + \", \" + fmtPct(getVal(\"maxDrop\"))\r\n    );\r\n  }\r\n\r\n  setTextIn(\r\n    tplRoot,\r\n    \"tsCablePdfCalcTempA\",\r\n    fmtTemp(getVal(\"ambientTemp\")) + \", \" + insulationLabel(getVal(\"insulationType\"))\r\n  );\r\n\r\n  setTextIn(tplRoot, \"tsCablePdfCalcInstallA\", selectText(\"installMethod\"));\r\n\r\n  \/\/ =========\r\n  \/\/ Ber\u00e4kningsdata, Kabel B\r\n  \/\/ =========\r\n  if (hasB) {\r\n    setTextIn(tplRoot, \"tsCablePdfCalcModeB\", \"New cable\");\r\n\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfCalcElmB\",\r\n      fmtKw(getVal(\"power2\")) + \", \" + fmtM(getVal(\"length2\")) + \", \" + fmtPct(getVal(\"maxDrop2\"))\r\n    );\r\n\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfCalcTempB\",\r\n      fmtTemp(getVal(\"ambientTemp2\")) + \", \" + insulationLabel(getVal(\"insulationType2\"))\r\n    );\r\n\r\n    setTextIn(tplRoot, \"tsCablePdfCalcInstallB\", selectText(\"installMethod2\"));\r\n  }\r\n\r\n  \/\/ =========\r\n  \/\/ Kabelresultat\r\n  \/\/ =========\r\n  function materialSv(mat){ return (mat === \"Copper\") ? \"copper\" : \"aluminium\"; }\r\n\r\n  if (lastResult.a) {\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfResCableA\",\r\n      String(lastResult.a.crossSection).replace(\".\", \",\") + \" mm\u00b2 \" + materialSv(lastResult.a.material)\r\n    );\r\n\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfResCondA\",\r\n      conductorLabel(mapConductor(getVal(\"conductorConfigA\")))\r\n    );\r\n  }\r\n\r\n  if (hasB && lastResult.b) {\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfResCableB\",\r\n      String(lastResult.b.crossSection).replace(\".\", \",\") + \" mm\u00b2 \" + materialSv(lastResult.b.material)\r\n    );\r\n\r\n    setTextIn(\r\n      tplRoot,\r\n      \"tsCablePdfResCondB\",\r\n      conductorLabel(mapConductor(getVal(\"conductorConfigB\")))\r\n    );\r\n  }\r\n\r\n  var totalDrop = toNumber(lastResult.totalDropPct);\r\n  var dropTxt = isFinite(totalDrop)\r\n    ? (hasB ? (\"Serie: \" + totalDrop.toFixed(2).replace(\".\", \",\") + \" %\") : (totalDrop.toFixed(2).replace(\".\", \",\") + \" %\"))\r\n    : \"-\";\r\n  setTextIn(tplRoot, \"tsCablePdfResDrop\", dropTxt);\r\n\r\n  \/\/ Logo\r\nvar logo = tplRoot.querySelector(\"#tsCablePdfBrandLogo\");\r\nif (logo) {\r\n  var url = resolveBrandLogoUrl();\r\n  if (!url) url = logo.getAttribute(\"data-logo-url\") || logo.src;\r\n\r\n  if (url) {\r\n    logo.setAttribute(\"crossorigin\", \"anonymous\");\r\n    logo.referrerPolicy = \"no-referrer\";\r\n    \/\/ cache-bust f\u00f6r att undvika att html2canvas tar en \"tom\" bild\r\n    logo.src = url + (url.indexOf(\"?\") > -1 ? \"&\" : \"?\") + \"cb=\" + Date.now();\r\n    logo.style.display = \"block\";\r\n  } else {\r\n    logo.style.display = \"none\";\r\n  }\r\n}\r\n}\r\n\r\n\r\n\r\n  function getJsPdfCtor(){\r\n    if (window.jspdf && window.jspdf.jsPDF) return window.jspdf.jsPDF;\r\n    if (window.jsPDF) return window.jsPDF;\r\n    return null;\r\n  }\r\n\r\n  var isPdfBusy = false;\r\n\r\n  async function createPdf(){\r\n    var lastResult = getLastOk();\r\n    if (!lastResult) { alert(\"K\u00f6r en ber\u00e4kning innan du skapar PDF.\"); return; }\r\n\r\n    if (!window.html2canvas) { alert(\"html2canvas saknas p\u00e5 sidan.\"); return; }\r\n    var jsPdfCtor = getJsPdfCtor();\r\n    if (!jsPdfCtor) { alert(\"jsPDF saknas p\u00e5 sidan.\"); return; }\r\n\r\n    if (isPdfBusy) return;\r\n    isPdfBusy = true;\r\n\r\n    try {\r\n      pdfHost.innerHTML = \"\";\r\n\r\n      var tpl = root.querySelector(\"#tsCablePdfTemplate\");\r\n      if (!tpl) { alert(\"Hittar inte PDF mallen (tsCablePdfTemplate).\"); return; }\r\n\r\n      var clone = tpl.cloneNode(true);\r\n      clone.id = \"tsCablePdfTemplateRender\";\r\n      clone.classList.remove(\"ts-hidden\");\r\n      clone.setAttribute(\"aria-hidden\", \"false\");\r\n\r\n      pdfHost.appendChild(clone);\r\n\r\n      fillCablePdfTemplate(lastResult, clone);\r\n\r\n      await new Promise(function (resolve) {\r\n        requestAnimationFrame(function () {\r\n          requestAnimationFrame(resolve);\r\n        });\r\n      });\r\n\r\n      var canvas = await window.html2canvas(clone, {\r\n        scale: 2,\r\n        useCORS: true,\r\n        backgroundColor: \"#ffffff\",\r\n        logging: false,\r\n        scrollX: 0,\r\n        scrollY: 0,\r\n        windowWidth: 794\r\n      });\r\n\r\n      var imgData = canvas.toDataURL(\"image\/jpeg\", 0.95);\r\n\r\n      var pdf = new jsPdfCtor(\"p\", \"mm\", \"a4\");\r\n      var pageWidth = pdf.internal.pageSize.getWidth();\r\n      var imgWidth = pageWidth;\r\n      var imgHeight = (canvas.height * imgWidth) \/ canvas.width;\r\n\r\n      pdf.addImage(imgData, \"JPEG\", 0, 0, imgWidth, imgHeight);\r\n\r\n      function nowCompactDate(){\r\n        var d = new Date();\r\n        var yyyy = d.getFullYear();\r\n        var mm = String(d.getMonth() + 1).padStart(2, \"0\");\r\n        var dd = String(d.getDate()).padStart(2, \"0\");\r\n        return String(yyyy) + mm + dd;\r\n      }\r\n\r\n      function sanitizeFilenamePart(s){\r\n        return String(s || \"\")\r\n          .trim()\r\n          .replace(\/[\\\\\\\/:*?\"<>|]+\/g, \"\")\r\n          .replace(\/\\s+\/g, \" \");\r\n      }\r\n\r\n      var dateStamp = nowCompactDate();\r\n      var projectNameRaw = textValue(q(\"tsProjectName\"));\r\n      var projectNameSafe = sanitizeFilenamePart(projectNameRaw);\r\n\r\n      var filename = projectNameSafe\r\n        ? (\"Kabelkalkylator_\" + dateStamp + \"_\" + projectNameSafe + \".pdf\")\r\n        : (\"Kabelkalkylator_\" + dateStamp + \".pdf\");\r\n\r\n      pdf.save(filename);\r\n    } catch (err) {\r\n      console.error(err);\r\n      alert(\"Kunde inte skapa PDF. Se console f\u00f6r detaljer.\");\r\n    } finally {\r\n      isPdfBusy = false;\r\n      pdfHost.innerHTML = \"\";\r\n    }\r\n  }\r\n\r\n  pdfButton.addEventListener(\"click\", function(e){\r\n    e.preventDefault();\r\n    createPdf();\r\n  }, true);\r\n\r\n  root.addEventListener(\"ts:cableCalculated\", function(){ ensureDocVisibility(); }, true);\r\n  root.addEventListener(\"input\", function(){ ensureDocVisibility(); }, true);\r\n  root.addEventListener(\"change\", function(){ ensureDocVisibility(); }, true);\r\n\r\n  setHidden(docSection, true);\r\n  ensureDocVisibility();\r\n\r\n  root.__tsCableDoc = { ensure: ensureDocVisibility };\r\n}\r\n  \r\n  \r\n  \r\n  \r\n  \r\n  \r\n\r\n  function initAll() {\r\n    var roots = getAllCableRoots();\r\n    for (var i = 0; i < roots.length; i++) {\r\n      initCableCalculatorForRoot(roots[i]);\r\n      initCablePdfForRoot(roots[i]);\r\n    }\r\n  }\r\n\r\n  initAll();\r\n\r\n  document.addEventListener(\"DOMContentLoaded\", function(){ initAll(); });\r\n\r\n\r\nvar wrap = document.querySelector(\"#toolSuiteWrap\") || document.body;\r\n\r\nvar pending = false;\r\nvar obs = new MutationObserver(function(){\r\n  if (pending) return;\r\n  pending = true;\r\n  requestAnimationFrame(function(){\r\n    pending = false;\r\n    initAll();\r\n  });\r\n});\r\n\r\nobs.observe(wrap, { childList:true, subtree:true });\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bb782d4 elementor-hidden-desktop elementor-hidden-laptop elementor-hidden-tablet_extra elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-html\" data-id=\"bb782d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\r\n(function () {\r\n  function toNumber(value) {\r\n    if (value === null || value === undefined) return NaN;\r\n    var str = String(value).trim().replace(',', '.');\r\n    if (!str) return NaN;\r\n    var n = parseFloat(str);\r\n    return isNaN(n) ? NaN : n;\r\n  }\r\n\r\n  function formatNumber(value, decimals) {\r\n    var n = toNumber(value);\r\n    if (!isFinite(n)) return '-';\r\n    var d = typeof decimals === 'number' ? decimals : 1;\r\n    return n.toLocaleString('sv-SE', { minimumFractionDigits: d, maximumFractionDigits: d });\r\n  }\r\n\r\n  function normalizeText(value) {\r\n    return String(value || '').toLowerCase().replace(\/\\s+\/g, ' ').trim();\r\n  }\r\n\r\n  var panelsList      = Array.isArray(window.ssoPanels)        ? window.ssoPanels        : [];\r\n  var sysconfProducts = Array.isArray(window.sysconfProducts)  ? window.sysconfProducts  : [];\r\n  var batteryList     = Array.isArray(window.sysconfBatteries) ? window.sysconfBatteries : [];\r\n\r\n  function buildIdMap(list) {\r\n    var map = {};\r\n    list.forEach(function (item, idx) {\r\n      if (!item) return;\r\n      var id = (typeof item.id !== 'undefined') ? String(item.id) : String(idx);\r\n      map[id] = item;\r\n    });\r\n    return map;\r\n  }\r\n\r\n  var panelMap   = buildIdMap(panelsList);\r\n  var batteryMap = buildIdMap(batteryList);\r\n\r\n  var sortedEnergyHubProducts = sysconfProducts\r\n    .slice()\r\n    .filter(function (p) {\r\n      return p && isFinite(toNumber(p.max_power)) && toNumber(p.max_power) > 0;\r\n    })\r\n    .sort(function (a, b) {\r\n      return toNumber(a.max_power) - toNumber(b.max_power);\r\n    });\r\n\r\n  var form               = document.getElementById('sysconfCalculatorForm');\r\n  var numPanelsInput     = document.getElementById('sysconfNumPanels');\r\n  var panelSelect        = document.getElementById('sysconfPanelSelect');\r\n  var manualModelGroup   = document.getElementById('sysconfManualModelGroup');\r\n  var manualModelInput   = document.getElementById('sysconfManualModel');\r\n  var panelDataGroup     = document.getElementById('sysconfPanelDataGroup');\r\n\r\n  var pmaxInput = document.getElementById('sysconfPanelPmax');\r\n  var vmpInput  = document.getElementById('sysconfPanelVmp');\r\n  var impInput  = document.getElementById('sysconfPanelImp');\r\n\r\n  var batterySelect = document.getElementById('sysconfBatterySelect');\r\n  var numEsoSelect  = document.getElementById('sysconfNumEso');\r\n  var calcBtn       = document.getElementById('sysconfCalcBtn');\r\n\r\n  var messageBox     = document.getElementById('sysconfMessage');\r\n\r\n  var resultWrap     = document.getElementById('sysconfResult');\r\n  var resInstalledKw = document.getElementById('sysconfResInstalledPower');\r\n  var resPanelsPerSso = document.getElementById('sysconfResPanelsPerSso');\r\n  var resMaxPanelsPerSso = document.getElementById('sysconfResMaxPanelsPerSso');\r\n  var resArticlesBody = document.getElementById('sysconfResArticlesBody');\r\n\r\n  if (!form) return;\r\n\r\n  var hasCalculated = false;\r\n\r\n  function showMessage(text) {\r\n    if (!messageBox) return;\r\n    if (!text) {\r\n      messageBox.style.display = 'none';\r\n      messageBox.textContent = '';\r\n      return;\r\n    }\r\n    messageBox.style.display = '';\r\n    messageBox.textContent = text;\r\n  }\r\n\r\n  function clearText(el) {\r\n    if (!el) return;\r\n    el.textContent = '';\r\n  }\r\n\r\n  function renderArticles(articles) {\r\n    if (!resArticlesBody) return;\r\n    while (resArticlesBody.firstChild) resArticlesBody.removeChild(resArticlesBody.firstChild);\r\n\r\n    if (!articles || !articles.length) return;\r\n\r\n    articles.forEach(function (row) {\r\n      var tr = document.createElement('tr');\r\n      var tdQty = document.createElement('td');\r\n      var tdEnr = document.createElement('td');\r\n      var tdName = document.createElement('td');\r\n\r\n      tdQty.textContent = (row.qty != null && row.qty !== '') ? row.qty + ' st' : '';\r\n      tdEnr.textContent = row.enr || '';\r\n      tdName.textContent = row.name || '';\r\n\r\n      tr.appendChild(tdQty);\r\n      tr.appendChild(tdEnr);\r\n      tr.appendChild(tdName);\r\n\r\n      resArticlesBody.appendChild(tr);\r\n    });\r\n  }\r\n\r\n  function hideResultUi() {\r\n    if (resultWrap) {\r\n      resultWrap.classList.remove('is-visible');\r\n      resultWrap.classList.add('is-hidden');\r\n    }\r\n    clearText(resInstalledKw);\r\n    clearText(resPanelsPerSso);\r\n    clearText(resMaxPanelsPerSso);\r\n    renderArticles([]);\r\n  }\r\n\r\n  function showResultUi() {\r\n    if (resultWrap) {\r\n      resultWrap.classList.remove('is-hidden');\r\n      resultWrap.classList.add('is-visible');\r\n    }\r\n  }\r\n\r\n  function markDirty() {\r\n    showMessage('');\r\n    if (!hasCalculated) return;\r\n    hasCalculated = false;\r\n    hideResultUi();\r\n  }\r\n\r\n  function initPanelSelect() {\r\n    if (!panelSelect) return;\r\n\r\n    while (panelSelect.firstChild) panelSelect.removeChild(panelSelect.firstChild);\r\n\r\n    var defaultOpt = document.createElement('option');\r\n    defaultOpt.value = '';\r\n    defaultOpt.textContent = 'V\u00e4lj panelmodell';\r\n    panelSelect.appendChild(defaultOpt);\r\n\r\n    panelsList.forEach(function (panel, index) {\r\n      if (!panel || !panel.modell) return;\r\n      var opt = document.createElement('option');\r\n      var id  = (typeof panel.id !== 'undefined') ? String(panel.id) : String(index);\r\n      opt.value = id;\r\n      opt.textContent = String(panel.modell);\r\n      panelSelect.appendChild(opt);\r\n    });\r\n\r\n    var manualOpt = document.createElement('option');\r\n    manualOpt.value = 'manual';\r\n    manualOpt.textContent = 'Annan panel, fyll i v\u00e4rden manuellt';\r\n    panelSelect.appendChild(manualOpt);\r\n  }\r\n\r\n  function initBatterySelect() {\r\n    if (!batterySelect) return;\r\n\r\n    while (batterySelect.firstChild) batterySelect.removeChild(batterySelect.firstChild);\r\n\r\n    var defaultOpt = document.createElement('option');\r\n    defaultOpt.value = '';\r\n    defaultOpt.textContent = 'V\u00e4lj batterityp';\r\n    batterySelect.appendChild(defaultOpt);\r\n\r\n    batteryList.forEach(function (batt, idx) {\r\n      if (!batt || !batt.name) return;\r\n\r\n      var id     = (typeof batt.id !== 'undefined') ? String(batt.id) : String(idx);\r\n      var energy = toNumber(batt.energy_kwh);\r\n\r\n      var opt = document.createElement('option');\r\n      opt.value = id;\r\n      opt.textContent = isFinite(energy)\r\n        ? (batt.name + ' ' + formatNumber(energy, 2) + ' kWh')\r\n        : batt.name;\r\n\r\n      batterySelect.appendChild(opt);\r\n    });\r\n\r\n    updateEsoOptions();\r\n  }\r\n\r\n  function calculateBatteryPowerKw(energyKwh, esoCount) {\r\n    var e = toNumber(energyKwh);\r\n    var n = toNumber(esoCount);\r\n    if (!isFinite(e) || e <= 0 || !isFinite(n) || n <= 0) return NaN;\r\n    return Math.round((e \/ 5) * n);\r\n  }\r\n\r\n  function updateEsoOptions() {\r\n    if (!numEsoSelect) return;\r\n\r\n    while (numEsoSelect.firstChild) numEsoSelect.removeChild(numEsoSelect.firstChild);\r\n\r\n    var defaultOpt = document.createElement('option');\r\n    defaultOpt.value = '';\r\n    defaultOpt.textContent = 'V\u00e4lj...';\r\n    numEsoSelect.appendChild(defaultOpt);\r\n\r\n    if (!batterySelect || !batterySelect.value || !batteryMap[batterySelect.value]) return;\r\n\r\n    var batt = batteryMap[batterySelect.value];\r\n    var e = toNumber(batt.energy_kwh);\r\n    if (!isFinite(e) || e <= 0) return;\r\n\r\n    [1, 2].forEach(function (n) {\r\n      var powerKw = calculateBatteryPowerKw(e, n);\r\n      if (!isFinite(powerKw) || powerKw <= 0) return;\r\n\r\n      var opt = document.createElement('option');\r\n      opt.value = String(n);\r\n      opt.textContent = formatNumber(powerKw, 0) + ' kW';\r\n      numEsoSelect.appendChild(opt);\r\n    });\r\n  }\r\n\r\n  function setPanelInputsReadOnly(flag) {\r\n    [pmaxInput, vmpInput, impInput].forEach(function (el) {\r\n      if (!el) return;\r\n      el.readOnly = flag;\r\n    });\r\n  }\r\n\r\n  function setPanelInputsFromPanel(panel) {\r\n    if (!pmaxInput || !vmpInput || !impInput) return;\r\n\r\n    if (!panel) {\r\n      pmaxInput.value = '';\r\n      vmpInput.value  = '';\r\n      impInput.value  = '';\r\n      return;\r\n    }\r\n\r\n    pmaxInput.value = (panel.pmax != null) ? panel.pmax : '';\r\n    vmpInput.value  = (panel.vmp  != null) ? panel.vmp  : '';\r\n    impInput.value  = (panel.imp  != null) ? panel.imp  : '';\r\n  }\r\n\r\n  function setPanelDataVisibility(isManual) {\r\n    if (manualModelGroup) manualModelGroup.style.display = isManual ? '' : 'none';\r\n    if (panelDataGroup) panelDataGroup.style.display = isManual ? '' : 'none';\r\n\r\n    setPanelInputsReadOnly(!isManual);\r\n\r\n    if (!isManual) {\r\n      setPanelInputsFromPanel(null);\r\n    }\r\n  }\r\n\r\n  function buildPanelForCalculation() {\r\n    if (!panelSelect) return null;\r\n\r\n    var panelId = panelSelect.value;\r\n\r\n    if (panelId === 'manual') {\r\n      return {\r\n        model: (manualModelInput && manualModelInput.value) ? manualModelInput.value : 'Annan panel (manuell)',\r\n        pmax: toNumber(pmaxInput ? pmaxInput.value : ''),\r\n        vmp:  toNumber(vmpInput ? vmpInput.value : ''),\r\n        imp:  toNumber(impInput ? impInput.value : '')\r\n      };\r\n    }\r\n\r\n    if (!panelId || !panelMap[panelId]) return null;\r\n\r\n    var src = panelMap[panelId];\r\n    return {\r\n      model: src.modell || '',\r\n      pmax:  toNumber(src.pmax),\r\n      vmp:   toNumber(src.vmp),\r\n      imp:   toNumber(src.imp)\r\n    };\r\n  }\r\n\r\n  function handlePanelSelectionChange() {\r\n    if (!panelSelect) return;\r\n\r\n    var isManual = (panelSelect.value === 'manual');\r\n    setPanelDataVisibility(isManual);\r\n\r\n    if (!isManual && panelMap[panelSelect.value]) {\r\n      setPanelInputsFromPanel(panelMap[panelSelect.value]);\r\n    }\r\n\r\n    markDirty();\r\n  }\r\n\r\n  function selectEnergyHubProduct(systemPowerKw) {\r\n    if (!sortedEnergyHubProducts.length || !isFinite(systemPowerKw) || systemPowerKw <= 0) return null;\r\n\r\n    for (var i = 0; i < sortedEnergyHubProducts.length; i++) {\r\n      var p = sortedEnergyHubProducts[i];\r\n      var limit = toNumber(p.max_power);\r\n      if (!isFinite(limit) || limit <= 0) continue;\r\n      if (systemPowerKw <= limit + 1e-6) return p;\r\n    }\r\n\r\n    return sortedEnergyHubProducts[sortedEnergyHubProducts.length - 1];\r\n  }\r\n\r\n  function findProductByBatteryAndType(batteryName, type) {\r\n    var bn = normalizeText(batteryName);\r\n    var typeTokens = (type === 'module') ? ['module', 'modul'] : ['controller', 'kontroller'];\r\n\r\n    for (var i = 0; i < sysconfProducts.length; i++) {\r\n      var p = sysconfProducts[i];\r\n      if (!p || !p.name) continue;\r\n\r\n      var pn = normalizeText(p.name);\r\n      if (pn.indexOf(bn) === -1) continue;\r\n\r\n      for (var t = 0; t < typeTokens.length; t++) {\r\n        if (pn.indexOf(typeTokens[t]) !== -1) return p;\r\n      }\r\n    }\r\n\r\n    return null;\r\n  }\r\n\r\n  function findEsoProduct() {\r\n    for (var i = 0; i < sysconfProducts.length; i++) {\r\n      var p = sysconfProducts[i];\r\n      if (!p || !p.name) continue;\r\n      if (normalizeText(p.name).indexOf('eso') !== -1) return p;\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function findPowerCaseProduct() {\r\n    for (var i = 0; i < sysconfProducts.length; i++) {\r\n      var p = sysconfProducts[i];\r\n      if (!p || !p.name) continue;\r\n      if (normalizeText(p.name).indexOf('powercase') !== -1) return p;\r\n    }\r\n    return null;\r\n  }\r\n\r\n  function buildArticles(energyHubProduct, numSso, selectedBattery, esoCount) {\r\n    var articles = [];\r\n\r\n    if (energyHubProduct) {\r\n      articles.push({ qty: 1, enr: energyHubProduct.enr || '', name: energyHubProduct.name || 'EnergyHub' });\r\n    }\r\n\r\n    if (isFinite(numSso) && numSso > 0) {\r\n      articles.push({ qty: numSso, enr: '5289195', name: 'SSO Single' });\r\n    }\r\n\r\n    if (selectedBattery && selectedBattery.name) {\r\n      var modules = toNumber(selectedBattery.modules);\r\n      var controllers = toNumber(selectedBattery.controllers);\r\n\r\n      var moduleProduct = findProductByBatteryAndType(selectedBattery.name, 'module');\r\n      var controllerProduct = findProductByBatteryAndType(selectedBattery.name, 'controller');\r\n\r\n      if (isFinite(controllers) && controllers > 0) {\r\n        articles.push({\r\n          qty: controllers,\r\n          enr: controllerProduct && controllerProduct.enr ? controllerProduct.enr : '',\r\n          name: controllerProduct && controllerProduct.name ? controllerProduct.name : selectedBattery.name + ' controller'\r\n        });\r\n      }\r\n\r\n      if (isFinite(modules) && modules > 0) {\r\n        articles.push({\r\n          qty: modules,\r\n          enr: moduleProduct && moduleProduct.enr ? moduleProduct.enr : '',\r\n          name: moduleProduct && moduleProduct.name ? moduleProduct.name : selectedBattery.name + ' module'\r\n        });\r\n      }\r\n\r\n      var esoProduct = findEsoProduct();\r\n      if (esoProduct && isFinite(esoCount) && esoCount > 0) {\r\n        articles.push({ qty: esoCount, enr: esoProduct.enr || '', name: esoProduct.name || 'ESO' });\r\n\r\n        var powerCaseProduct = findPowerCaseProduct();\r\n        articles.push({\r\n          qty: 1,\r\n          enr: powerCaseProduct && powerCaseProduct.enr ? powerCaseProduct.enr : '',\r\n          name: powerCaseProduct && powerCaseProduct.name ? powerCaseProduct.name : 'PowerCase'\r\n        });\r\n      }\r\n    }\r\n\r\n    return articles;\r\n  }\r\n\r\n  function formatPanelsPerSsoGrouped(totalPanels, ssoCount) {\r\n    var total = Math.floor(toNumber(totalPanels));\r\n    var n = Math.floor(toNumber(ssoCount));\r\n    if (!isFinite(total) || total <= 0 || !isFinite(n) || n <= 0) return '-';\r\n\r\n    var base = Math.floor(total \/ n);\r\n    var rem  = total % n;\r\n\r\n    var per = [];\r\n    for (var i = 0; i < n; i++) {\r\n      per.push(i < rem ? (base + 1) : base);\r\n    }\r\n\r\n    var parts = [];\r\n    var start = 0;\r\n\r\n    while (start < per.length) {\r\n      var val = per[start];\r\n      var end = start;\r\n      while (end + 1 < per.length && per[end + 1] === val) end++;\r\n\r\n      var from = start + 1;\r\n      var to = end + 1;\r\n\r\n      if (from === to) parts.push(val + ' st SSO nr ' + from);\r\n      else parts.push(val + ' st SSO nr ' + from + '-' + to);\r\n\r\n      start = end + 1;\r\n    }\r\n\r\n    return parts.join(', ');\r\n  }\r\n\r\n  function calculateSystem() {\r\n    showMessage('');\r\n\r\n    var batteryChosen = !!(batterySelect && batterySelect.value && batteryMap[batterySelect.value]);\r\n    var esoChosen = !!(numEsoSelect && numEsoSelect.value);\r\n\r\n    if (batteryChosen && !esoChosen) {\r\n      hasCalculated = false;\r\n      hideResultUi();\r\n      showMessage('V\u00e4lj batterieffekt f\u00f6r att kunna ber\u00e4kna med valt batteri.');\r\n      return;\r\n    }\r\n\r\n    var solarValid = false;\r\n    var ssoCount = NaN;\r\n    var installedKwPmax = NaN;\r\n    var installedKwVI = NaN;\r\n    var solarPowerKw = NaN;\r\n    var maxPanelsPerSso = NaN;\r\n\r\n    var selectedBattery = null;\r\n    var batterySelected = false;\r\n\r\n    var esoCount = NaN;\r\n    var batteryPowerKw = NaN;\r\n    var batteryPowerValid = false;\r\n\r\n    var energyHubProduct = null;\r\n\r\n    var panel = buildPanelForCalculation();\r\n    var numPanels = toNumber(numPanelsInput ? numPanelsInput.value : '');\r\n\r\n    if (panel && isFinite(numPanels) && numPanels > 0) {\r\n      var vmp = toNumber(panel.vmp);\r\n      var imp = toNumber(panel.imp);\r\n\r\n      if (isFinite(vmp) && vmp > 0 && isFinite(imp) && imp > 0) {\r\n        var recVmp = (imp > 13.5) ? 600 : 640;\r\n        maxPanelsPerSso = Math.floor(recVmp \/ vmp);\r\n\r\n        if (isFinite(maxPanelsPerSso) && maxPanelsPerSso >= 1) {\r\n          var totalPanels = numPanels;\r\n          ssoCount = 1;\r\n\r\n          while (Math.ceil(totalPanels \/ ssoCount) > maxPanelsPerSso) {\r\n            ssoCount++;\r\n          }\r\n\r\n          if (isFinite(panel.pmax) && panel.pmax > 0) installedKwPmax = (panel.pmax * totalPanels) \/ 1000;\r\n          installedKwVI = (vmp * imp * totalPanels) \/ 1000;\r\n\r\n          solarPowerKw = isFinite(installedKwPmax) ? installedKwPmax : installedKwVI;\r\n          solarValid = isFinite(solarPowerKw) && solarPowerKw > 0;\r\n        }\r\n      }\r\n    }\r\n\r\n    if (batteryChosen) {\r\n      selectedBattery = batteryMap[batterySelect.value];\r\n      batterySelected = true;\r\n\r\n      if (esoChosen) {\r\n        esoCount = toNumber(numEsoSelect.value);\r\n        batteryPowerKw = calculateBatteryPowerKw(selectedBattery.energy_kwh, esoCount);\r\n        batteryPowerValid = isFinite(batteryPowerKw) && batteryPowerKw > 0;\r\n      }\r\n    }\r\n\r\n    if (solarValid) {\r\n      energyHubProduct = selectEnergyHubProduct(solarPowerKw);\r\n    } else if (batterySelected) {\r\n      if (batteryPowerValid) energyHubProduct = selectEnergyHubProduct(batteryPowerKw);\r\n      else energyHubProduct = selectEnergyHubProduct(toNumber(selectedBattery.energy_kwh));\r\n    }\r\n\r\n    if (!solarValid && !batterySelected) {\r\n      hasCalculated = false;\r\n      hideResultUi();\r\n      return;\r\n    }\r\n\r\n    showResultUi();\r\n\r\n    if (resInstalledKw) {\r\n      resInstalledKw.textContent = solarValid\r\n        ? (isFinite(installedKwPmax) ? formatNumber(installedKwPmax, 1) + ' kW (Pmax)' : '-')\r\n        : '-';\r\n    }\r\n\r\n    if (resPanelsPerSso) {\r\n      resPanelsPerSso.textContent = (solarValid && isFinite(ssoCount))\r\n        ? formatPanelsPerSsoGrouped(numPanels, ssoCount)\r\n        : '-';\r\n    }\r\n\r\n    if (resMaxPanelsPerSso) {\r\n      resMaxPanelsPerSso.textContent = (solarValid && isFinite(maxPanelsPerSso)) ? (maxPanelsPerSso + ' st') : '-';\r\n    }\r\n\r\n    var articles = buildArticles(\r\n      energyHubProduct,\r\n      solarValid ? ssoCount : NaN,\r\n      batterySelected ? selectedBattery : null,\r\n      batteryPowerValid ? esoCount : NaN\r\n    );\r\n\r\n    renderArticles(articles);\r\n  }\r\n\r\n  initPanelSelect();\r\n  initBatterySelect();\r\n\r\n  setPanelDataVisibility(false);\r\n  hideResultUi();\r\n  showMessage('');\r\n\r\n  if (panelSelect) panelSelect.addEventListener('change', handlePanelSelectionChange);\r\n\r\n  if (batterySelect) {\r\n    batterySelect.addEventListener('change', function () {\r\n      updateEsoOptions();\r\n      markDirty();\r\n    });\r\n  }\r\n\r\n  if (numEsoSelect) {\r\n    numEsoSelect.addEventListener('change', function () {\r\n      showMessage('');\r\n      markDirty();\r\n    });\r\n  }\r\n\r\n  if (numPanelsInput) numPanelsInput.addEventListener('input', markDirty);\r\n  if (manualModelInput) manualModelInput.addEventListener('input', markDirty);\r\n  if (pmaxInput) pmaxInput.addEventListener('input', markDirty);\r\n  if (vmpInput) vmpInput.addEventListener('input', markDirty);\r\n  if (impInput) impInput.addEventListener('input', markDirty);\r\n\r\n  if (calcBtn) {\r\n    calcBtn.addEventListener('click', function () {\r\n      showMessage('');\r\n      hasCalculated = true;\r\n      calculateSystem();\r\n    });\r\n  }\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d279094 elementor-widget elementor-widget-html\" data-id=\"d279094\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\r\n    \r\n(function () {\r\n  function qs(sel, root){ return (root || document).querySelector(sel); }\r\n  function qsa(sel, root){ return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }\r\n\r\n  var wrap         = qs(\"#toolSuiteWrap\");\r\n  var chooser      = qs(\"#toolSuiteChooser\");\r\n  var chooserAlert = qs(\"#tsChooserAlert\");\r\n  var separator    = qs(\"#tsCalcSeparator\");\r\n  var activeTitle  = qs(\"#tsActiveCalcTitle\");\r\n\r\n  if (!wrap || !chooser) return;\r\n\r\n  var views = {\r\n    system: qs(\"#viewSystem\"),\r\n    pv:     qs(\"#viewPv\"),\r\n    cable:  qs(\"#viewCable\"),\r\n    pdf:    qs(\"#viewPdfExport\")\r\n  };\r\n\r\n  var mounted = { pv:false, cable:false, system:false };\r\n\r\n  function keyLabel(key){\r\n    if (key === \"system\") return \"Systemkalkylator\";\r\n    if (key === \"pv\")     return \"SSO kalkylator\";\r\n    if (key === \"cable\")  return \"Kabelkalkylator\";\r\n    if (key === \"pdf\")    return \"PDF export\";\r\n    return \"\";\r\n  }\r\n\r\n  function hideChooserAlert(){\r\n    if (!chooserAlert) return;\r\n    chooserAlert.classList.add(\"ts-hidden\");\r\n    chooserAlert.textContent = \"\";\r\n  }\r\n  function showChooserAlert(msg){\r\n    if (!chooserAlert) return;\r\n    chooserAlert.textContent = msg || \"\";\r\n    chooserAlert.classList.remove(\"ts-hidden\");\r\n  }\r\n\r\n  function moveNodeChildren(fromEl, toEl){\r\n    if (!fromEl || !toEl) return;\r\n    while (fromEl.firstChild) toEl.appendChild(fromEl.firstChild);\r\n  }\r\n\r\n  function hideAllViews(){\r\n    Object.keys(views).forEach(function(k){\r\n      if (views[k]) views[k].classList.add(\"ts-hidden\");\r\n    });\r\n  }\r\n\r\n  function setActiveButton(activeKey){\r\n    qsa(\"[data-ts-btn]\", chooser).forEach(function (b) {\r\n      b.classList.remove(\"is-active\");\r\n      b.setAttribute(\"aria-pressed\", \"false\");\r\n    });\r\n    if (!activeKey) return;\r\n    var btn = qs('[data-ts-btn=\"' + activeKey + '\"]', chooser);\r\n    if (btn) {\r\n      btn.classList.add(\"is-active\");\r\n      btn.setAttribute(\"aria-pressed\", \"true\");\r\n    }\r\n  }\r\n\r\n  function showSeparator(key){\r\n    if (!separator) return;\r\n    separator.style.display = \"\";\r\n    if (activeTitle) activeTitle.textContent = \"\";\r\n  }\r\n\r\n  function hideSeparator(){\r\n    if (!separator) return;\r\n    separator.style.display = \"none\";\r\n    if (activeTitle) activeTitle.textContent = \"\";\r\n  }\r\n\r\n  function setUrlTool(key){\r\n    try{\r\n      var url = new URL(window.location.href);\r\n      if (key) url.searchParams.set(\"tool\", key);\r\n      else url.searchParams.delete(\"tool\");\r\n      window.history.replaceState({}, \"\", url.toString());\r\n    }catch(e){}\r\n  }\r\n\r\n  function getUrlTool(){\r\n    try{\r\n      return ((new URL(window.location.href)).searchParams.get(\"tool\") || \"\").toLowerCase();\r\n    }catch(e){ return \"\"; }\r\n  }\r\n\r\n  function mountHeader(viewEl, key){\r\n    var host = qs('[data-ts-mount=\"header\"]', viewEl);\r\n    if (!host) return;\r\n\r\n    host.innerHTML = \"\";\r\n\r\n    var card = document.createElement(\"div\");\r\n    card.className = \"ts-card\";\r\n    card.style.marginBottom = \"12px\";\r\n\r\n    var title = document.createElement(\"div\");\r\n    title.style.fontWeight = \"900\";\r\n    title.style.fontSize = \"16px\";\r\n    title.textContent = keyLabel(key);\r\n\r\n\r\n    host.appendChild(card);\r\n  }\r\n\r\nvar mounted = { pv:false, cable:false, system:false };\r\n\r\nfunction ensureMounted(key){\r\n  if (key === \"pv\" && !mounted.pv) {\r\n    var src = qs(\"#ssoCalculatorRoot\");\r\n    var dst = qs('[data-ts-mount=\"content\"]', views.pv);\r\n    if (!src || !dst) {\r\n      showChooserAlert(\"SSO-blocket saknas. Kontrollera att #ssoCalculatorRoot finns.\");\r\n    } else {\r\n      moveNodeChildren(src, dst);\r\n      mounted.pv = true;\r\n      if (typeof window.initSsoCalculator === \"function\") window.initSsoCalculator();\r\n    }\r\n  }\r\n\r\n  if (key === \"cable\" && !mounted.cable) {\r\n    var src2 = qs(\"#cableCalculatorRoot_tsCable2\");\r\n    var dst2 = qs('[data-ts-mount=\"content\"]', views.cable);\r\n    if (!src2 || !dst2) {\r\n      showChooserAlert(\"Kabelblocket saknas. Kontrollera att #cableCalculatorRoot finns.\");\r\n    } else {\r\n      moveNodeChildren(src2, dst2);\r\n      mounted.cable = true;\r\n      if (typeof window.initCableCalculator === \"function\") window.initCableCalculator();\r\n    }\r\n  }\r\n\r\n  if (key === \"system\" && !mounted.system) {\r\n    var src3 = qs(\"#systemCalculatorRoot\");\r\n    var dst3 = qs('[data-ts-mount=\"content\"]', views.system);\r\n\r\n    if (!src3 || !dst3) {\r\n      showChooserAlert(\"Systemblocket saknas. Kontrollera att #systemCalculatorRoot finns.\");\r\n    } else {\r\n      moveNodeChildren(src3, dst3);\r\n      mounted.system = true;\r\n      if (typeof window.initSystemCalculator === \"function\") window.initSystemCalculator();\r\n    }\r\n  }\r\n}\r\n\r\n\r\n  function showView(key){\r\n    hideChooserAlert();\r\n\r\n    if (!views[key]) {\r\n      showChooserAlert(\"Den valda kalkylatorn saknas. Kontrollera att vyn finns.\");\r\n      return;\r\n    }\r\n\r\n    ensureMounted(key);\r\n\r\n    hideAllViews();\r\n    setActiveButton(key);\r\n\r\n    showSeparator(key);\r\n    mountHeader(views[key], key);\r\n    views[key].classList.remove(\"ts-hidden\");\r\n\r\n    setUrlTool(key);\r\n\r\n    try{\r\n      separator.scrollIntoView({ behavior:\"smooth\", block:\"start\" });\r\n    }catch(e){}\r\n  }\r\n  \r\n  \/\/ Trigger layout pass after mount\/show (Elementor can cache widths)\r\ntry {\r\n  window.requestAnimationFrame(function () {\r\n    window.dispatchEvent(new Event(\"resize\"));\r\n  });\r\n} catch (e) {}\r\n\r\n\r\n\r\n  function clearAll(){\r\n    hideAllViews();\r\n    setActiveButton(\"\");\r\n    hideSeparator();\r\n    setUrlTool(\"\");\r\n  }\r\n\r\n  wrap.addEventListener(\"click\", function(e){\r\n    var btn = e.target && e.target.closest ? e.target.closest(\"[data-ts-go]\") : null;\r\n    if (!btn) return;\r\n\r\n    e.preventDefault();\r\n    var key = (btn.getAttribute(\"data-ts-go\") || \"\").toLowerCase();\r\n    if (!key) return;\r\n\r\n    showView(key);\r\n  });\r\n\r\n  clearAll();\r\n\r\n  var start = getUrlTool();\r\n  if (start && views[start]) showView(start);\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\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\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\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>Dimensioning tool Calculate how the Ferroamp system should be dimensioned and receive a complete documentation package. System calculator\u00a0Provides a complete bill of materials for the entire system, including PV string planning and DC cable sizing. SSO calculator\u00a0Used for calculating the PV panel configuration only. If the panels you intend to use are not available in [&hellip;]<\/p>\n","protected":false},"author":28,"featured_media":0,"parent":7203,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"hf_cat_page":[],"class_list":["post-23609","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Dimensioning tool - Ferroamp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Dimensioning tool - Ferroamp\" \/>\n<meta property=\"og:description\" content=\"Dimensioning tool Calculate how the Ferroamp system should be dimensioned and receive a complete documentation package. System calculator\u00a0Provides a complete bill of materials for the entire system, including PV string planning and DC cable sizing. SSO calculator\u00a0Used for calculating the PV panel configuration only. If the panels you intend to use are not available in [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/\" \/>\n<meta property=\"og:site_name\" content=\"Ferroamp\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-09T15:18:19+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/dimensioning-tool\\\/\",\"url\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/dimensioning-tool\\\/\",\"name\":\"Dimensioning tool - Ferroamp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/#website\"},\"datePublished\":\"2026-02-09T13:03:23+00:00\",\"dateModified\":\"2026-02-09T15:18:19+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/dimensioning-tool\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/dimensioning-tool\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/dimensioning-tool\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Installer\",\"item\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/installer\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Dimensioning tool\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/\",\"name\":\"Ferroamp\",\"description\":\"smart electricity control\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/ferroamp.com\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Dimensioning tool - Ferroamp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/","og_locale":"en_US","og_type":"article","og_title":"Dimensioning tool - Ferroamp","og_description":"Dimensioning tool Calculate how the Ferroamp system should be dimensioned and receive a complete documentation package. System calculator\u00a0Provides a complete bill of materials for the entire system, including PV string planning and DC cable sizing. SSO calculator\u00a0Used for calculating the PV panel configuration only. If the panels you intend to use are not available in [&hellip;]","og_url":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/","og_site_name":"Ferroamp","article_modified_time":"2026-02-09T15:18:19+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/","url":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/","name":"Dimensioning tool - Ferroamp","isPartOf":{"@id":"https:\/\/ferroamp.com\/en\/#website"},"datePublished":"2026-02-09T13:03:23+00:00","dateModified":"2026-02-09T15:18:19+00:00","breadcrumb":{"@id":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/ferroamp.com\/en\/installer\/dimensioning-tool\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ferroamp.com\/en\/"},{"@type":"ListItem","position":2,"name":"Installer","item":"https:\/\/ferroamp.com\/en\/installer\/"},{"@type":"ListItem","position":3,"name":"Dimensioning tool"}]},{"@type":"WebSite","@id":"https:\/\/ferroamp.com\/en\/#website","url":"https:\/\/ferroamp.com\/en\/","name":"Ferroamp","description":"smart electricity control","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ferroamp.com\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/pages\/23609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/users\/28"}],"replies":[{"embeddable":true,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/comments?post=23609"}],"version-history":[{"count":8,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/pages\/23609\/revisions"}],"predecessor-version":[{"id":23619,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/pages\/23609\/revisions\/23619"}],"up":[{"embeddable":true,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/pages\/7203"}],"wp:attachment":[{"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/media?parent=23609"}],"wp:term":[{"taxonomy":"hf_cat_page","embeddable":true,"href":"https:\/\/ferroamp.com\/en\/wp-json\/wp\/v2\/hf_cat_page?post=23609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}