{"id":9031,"date":"2026-01-29T00:15:50","date_gmt":"2026-01-28T21:15:50","guid":{"rendered":"https:\/\/ukraine.eu4business-ebrdcreditline.toyidea.info\/dashboard\/"},"modified":"2026-07-26T22:49:59","modified_gmt":"2026-07-26T19:49:59","slug":"dashboard","status":"publish","type":"page","link":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/","title":{"rendered":"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c"},"content":{"rendered":"<ul>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/02\/Small-Town-to-Big-Standards-02.jpg\" alt=\"\"><\/p>\n<h3>Impact <br class=\"uk-visible@m\" \/>Dashboard<\/h3>\n<div>\n<p>The EU4Business\u2013EBRD Credit Line <br class=\"uk-visible@m\" \/>supports MSMEs in <strong>Armenia<\/strong>, <strong>Georgia<\/strong>, <br class=\"uk-visible@m\" \/><strong>Moldova<\/strong> and <strong>Ukraine<\/strong> to invest, grow <br class=\"uk-visible@m\" \/>and align with EU standards.<\/p>\n<\/div>\n<\/li>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/02\/%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%BD%D1%8F_viber_2026-02-06_12-29-42-268.jpg\" alt=\"\"><\/p>\n<h3>Impact <br class=\"uk-visible@m\" \/>Dashboard<\/h3>\n<div>\n<p>The EU4Business\u2013EBRD Credit Line <br class=\"uk-visible@m\" \/>supports MSMEs in <strong>Armenia<\/strong>, <strong>Georgia<\/strong>, <br class=\"uk-visible@m\" \/><strong>Moldova<\/strong> and <strong>Ukraine<\/strong> to invest, grow <br class=\"uk-visible@m\" \/>and align with EU standards.<\/p>\n<\/div>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/Icon-5-color.svg\" alt=\"\"><\/p>\n<h3>item 1<\/h3>\n<div>This interactive dashboard presents the Programme\u2019s cumulative results across all participating countries \u2014 from financing volumes and supported businesses to energy savings, emissions reductions and jobs sustained<\/div>\n<\/li>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/Icon-3-color.svg\" alt=\"\"><\/p>\n<h3>item 1<\/h3>\n<div>Updated quarterly, it provides a transparent view of how EU-backed finance translates into tangible economic and environmental impact across the region<\/div>\n<\/li>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/Icon-4-color.svg\" alt=\"\"><\/p>\n<h3>item 1<\/h3>\n<div>Explore regional results or apply filters to see how the programme is delivering change where it matters most<\/div>\n<\/li>\n<li>\n<p>        <img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/05\/Icon-2-color.svg\" alt=\"\"><\/p>\n<h3>item 1<\/h3>\n<div>\n<h4>Exploring the data<\/h4>\n<p>Use the filter to explore programme results by Country. Charts update dynamically based on the selected filters.<\/p>\n<\/div>\n<\/li>\n<\/ul>\n<h3>Understanding <br class=\"uk-visible@m\" \/>the impact<\/h3>\n<div>Programme results are calculated using verified project data and standard methodologies applied across the Programme. Energy savings and emissions reductions are derived from efficiency improvements and renewable energy investments implemented by supported businesses<\/div>\n<h1>Financial Indicators<\/h1>\n<div id=\"dw_6a5a060e7540c\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table1:1\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label active\" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label \" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\" >Horizontal<\/option><option value=\"vertical\"  selected='selected'>Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\"  selected='selected'>Stacked<\/option><option value=\"false\" >Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e7540c\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e7540c\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e7540c';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[1],\"indicatorSpecs\":[\"table1:1\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"vertical\",\"barStacked\":true,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e7540c');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e7540c'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e7540c');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e7540c');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e7540c');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e7540c');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e7540c');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<div id=\"dw_6a5a060e7654a\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table1:2\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label \" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label active\" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\"  selected='selected'>Horizontal<\/option><option value=\"vertical\" >Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\" >Stacked<\/option><option value=\"false\"  selected='selected'>Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e7654a\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e7654a\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e7654a';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[2],\"indicatorSpecs\":[\"table1:2\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"horizontal\",\"barStacked\":false,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e7654a');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e7654a'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e7654a');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e7654a');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e7654a');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e7654a');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e7654a');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<h1>Indicators<\/h1>\n<div id=\"dw_6a5a060e773e7\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table2:3\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label active\" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label \" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\" >Horizontal<\/option><option value=\"vertical\"  selected='selected'>Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\"  selected='selected'>Stacked<\/option><option value=\"false\" >Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e773e7\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e773e7\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e773e7';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[3],\"indicatorSpecs\":[\"table2:3\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"vertical\",\"barStacked\":true,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e773e7');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e773e7'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e773e7');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e773e7');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e773e7');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e773e7');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e773e7');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<div id=\"dw_6a5a060e77c5b\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table2:4\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label \" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label active\" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\"  selected='selected'>Horizontal<\/option><option value=\"vertical\" >Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\" >Stacked<\/option><option value=\"false\"  selected='selected'>Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e77c5b\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e77c5b\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e77c5b';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[4],\"indicatorSpecs\":[\"table2:4\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"horizontal\",\"barStacked\":false,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e77c5b');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e77c5b'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e77c5b');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e77c5b');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e77c5b');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e77c5b');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e77c5b');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<div id=\"dw_6a5a060e78619\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table2:5\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label active\" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label \" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\" >Horizontal<\/option><option value=\"vertical\"  selected='selected'>Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\"  selected='selected'>Stacked<\/option><option value=\"false\" >Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e78619\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e78619\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e78619';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[5],\"indicatorSpecs\":[\"table2:5\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"vertical\",\"barStacked\":true,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e78619');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e78619'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e78619');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e78619');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e78619');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e78619');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e78619');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<h1>Energy Indicators<\/h1>\n<div id=\"dw_6a5a060e79492\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table3:6\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label \" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label active\" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\"  selected='selected'>Horizontal<\/option><option value=\"vertical\" >Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\" >Stacked<\/option><option value=\"false\"  selected='selected'>Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e79492\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e79492\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e79492';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[6],\"indicatorSpecs\":[\"table3:6\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"horizontal\",\"barStacked\":false,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e79492');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e79492'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e79492');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e79492');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e79492');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e79492');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e79492');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<div id=\"dw_6a5a060e7a395\" class=\"dashd-widget-container uk-margin-large-bottom\" \n        data-key=\"table1\" data-indicators=\"table3:7\" data-lang=\"en\" style=\"background: #fff; padding: 25px; border-radius: 8px; position: relative;\"><\/p>\n<div class=\"dashd-pdf-header\" style=\"display:none; margin-bottom: 25px; text-align: right; border-bottom: 2px solid #f0f0f1; padding-bottom: 15px;\">\n            <img src=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" style=\"width: 150px; height: auto;\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\" loading=\"eager\" decoding=\"sync\">        <\/div>\n<div class=\"dashd-country-btns uk-margin-small-bottom uk-flex uk-flex-wrap\" style=\"gap:5px;justify-content:center;\"><\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-bottom dashd-widget-topbar\">\n<h3 class=\"uk-h4 uk-margin-remove dashd-widget-title\" data-default-title=\"Analytics Overview\">Analytics Overview<\/h3>\n<div class=\"uk-flex uk-flex-column dashd-controls-stack\" style=\"align-items: flex-end; gap: 10px;\">\n<div class=\"uk-flex uk-flex-middle dashd-controls-desktop\" style=\"gap:10px;\">\n<div class=\"dashd-view-selector dashd-toggle-view\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-type=\"bar\">Bar<\/div>\n<div class=\"dashd-selector-label \" data-type=\"line\">Line<\/div>\n<div class=\"dashd-selector-label \" data-type=\"donut\">Donut<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-scale\" data-html2canvas-ignore=\"true\" style=\"display:none;\">\n<div class=\"dashd-selector-label active\" data-scale=\"linear\">Lin<\/div>\n<div class=\"dashd-selector-label \" data-scale=\"logarithmic\">Log<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-orientation\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label \" data-orientation=\"horizontal\">Horizontal<\/div>\n<div class=\"dashd-selector-label active\" data-orientation=\"vertical\">Vertical<\/div>\n<\/p><\/div>\n<div class=\"dashd-view-selector dashd-toggle-stacked\" data-html2canvas-ignore=\"true\" style=\"\">\n<div class=\"dashd-selector-label active\" data-stacked=\"true\">Stacked<\/div>\n<div class=\"dashd-selector-label \" data-stacked=\"false\">Normal<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-mobile-controls\" data-html2canvas-ignore=\"true\">\n                    <label class=\"dashd-mobile-field dashd-mobile-field-view\" style=\"display:none;\"><br \/>\n                        <span>View<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-view\"><option value=\"bar\"  selected='selected'>Bar<\/option><option value=\"line\" >Line<\/option><option value=\"donut\" >Donut<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-scale\" style=\"display:none;\"><br \/>\n                        <span>Scale<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-scale\"><option value=\"linear\"  selected='selected'>Linear<\/option><option value=\"logarithmic\" >Logarithmic<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-orientation\" style=\"\"><br \/>\n                        <span>Bars<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-orientation\"><option value=\"horizontal\" >Horizontal<\/option><option value=\"vertical\"  selected='selected'>Vertical<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-stacked\" style=\"\"><br \/>\n                        <span>Bar Type<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-stacked\"><option value=\"true\"  selected='selected'>Stacked<\/option><option value=\"false\" >Normal<\/option><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-year\" style=\"display:none;\"><br \/>\n                        <span>Year<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-year\"><\/select><br \/>\n                    <\/label><br \/>\n                    <label class=\"dashd-mobile-field dashd-mobile-field-quarter\" style=\"display:none;\"><br \/>\n                        <span>Quarter<\/span><br \/>\n                        <select class=\"dashd-mobile-select dashd-mobile-quarter\"><\/select><br \/>\n                    <\/label>\n                <\/div>\n<div class=\"dashd-periods-wrap uk-flex dashd-period-controls\" style=\"gap:10px;display:none;\">\n<div class=\"dashd-year-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<div class=\"dashd-q-btns uk-flex dashd-period-buttons\" style=\"gap:5px;\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"dashd-chart-box\" style=\"height:420px; background:#fff; padding:15px; border-radius:8px; border:1px solid #f0f0f0; position:relative; overflow: hidden;\">\n<div class=\"dashd-loader-overlay\" style=\"display: flex; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.7); z-index: 10; align-items: center; justify-content: center; backdrop-filter: blur(2px); transition: opacity 0.3s ease;\">\n<div style=\"width: 40px; height: 40px; border: 3px solid rgba(30, 135, 240, 0.2); border-radius: 50%; border-top-color: #1e87f0; animation: spin 1s ease-in-out infinite;\"><\/div>\n<\/p><\/div>\n<p>            <canvas class=\"dashd-canvas\"><\/canvas>\n        <\/div>\n<div class=\"uk-flex uk-flex-between uk-flex-middle uk-margin-top\">\n<div style=\"display: flex; gap: 15px; font-size: 13px;\" data-html2canvas-ignore=\"true\">\n                <span class=\"dashd-export-csv\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Data as CSV\"><br \/>\n                    <span class=\"dashicons dashicons-media-spreadsheet\" style=\"font-size:16px; line-height:1;\"><\/span> CSV<br \/>\n                <\/span><br \/>\n                <span class=\"dashd-export-pdf\" style=\"cursor:pointer; color:#1e87f0; display:flex; align-items:center; gap:4px; font-weight:600;\" title=\"Download Dashboard as PDF\"><br \/>\n                    <span class=\"dashicons dashicons-pdf\" style=\"font-size:16px; line-height:1;\"><\/span> PDF<br \/>\n                <\/span>\n            <\/div>\n<div id=\"toggle-dw_6a5a060e7a395\" style=\"cursor:pointer; user-select:none; display:flex; align-items:center; gap:10px;\" data-html2canvas-ignore=\"true\">\n<div class=\"dashd-hamburger\"><span><\/span><span><\/span><span><\/span><\/div>\n<div style=\"font-weight: 600; color: #1e87f0;\">View Detailed Table<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div id=\"tb-dw_6a5a060e7a395\" class=\"dashd-table-wrapper uk-margin-top\" style=\"display: none;\">\n<div class=\"dashd-table-scroll-container\">\n<table class=\"dashd-table\">\n<thead>\n<tr class=\"dashd-thead\"><\/tr>\n<\/thead>\n<tbody class=\"dashd-tbody\"><\/tbody>\n<\/table><\/div>\n<\/p><\/div>\n<div class=\"dashd-last-sync-time\" style=\"font-size: 11px; color: #94a3b8; text-align: right; margin-top: 10px; font-style: italic;\"><\/div>\n<\/p><\/div>\n<p><script data-dashd-widget-boot=\"1\">\n(function() {\n        const rootId = 'dw_6a5a060e7a395';\n        const config = {\"key\":\"table1\",\"indicatorIds\":[7],\"indicatorSpecs\":[\"table3:7\"],\"lang\":\"en\",\"colors\":[\"#336DFF\",\"#AF9BE2\",\"#3B82F6\",\"#BEE00F\",\"#7FD3F7\"],\"weight\":3,\"ajax\":\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-admin\/admin-ajax.php\",\"viewMode\":\"bar\",\"scaleMode\":\"linear\",\"isGated\":false,\"showViewToggle\":false,\"showScaleToggle\":false,\"showPeriods\":false,\"showBarControlsUI\":true,\"barOrientation\":\"vertical\",\"barStacked\":true,\"countryOrder\":[\"Ukraine\",\"Armenia\",\"Georgia\",\"Moldova\"],\"leadNonce\":\"d085cfcd46\"};\n        const startWidget = () => {\n            const root = document.getElementById(rootId);\n            if (!root) {\n                return false;\n            }\n            if (root.dataset.dashdInited === '1') {\n                return true;\n            }\n            root.dataset.dashdInited = '1';<\/p>\n<p>        const i18n = {\n            allCountries: \"All Countries\",\n            analyticsOverview: \"Analytics Overview\",\n            indicator: \"Indicator\",\n            trend: \"Trend\",\n            total: \"Total\",\n            lastUpdated: \"Last updated:\",\n            wait: \"Wait...\",\n            verifying: \"Verifying...\",\n            unlockAndDownload: \"Unlock &amp; Download\",\n            invalidEmail: \"Please enter a valid email address.\",\n            pdfLibsLoading: \"PDF libraries are still loading. Please try again in a second.\",\n            errorPdf: \"Error generating PDF.\",\n            errorServer: \"Server connection error.\",\n            errorGeneral: \"An error occurred.\"\n        };<\/p>\n<p>        let chart = null, rawData = null, trendData = null,\n            viewMode = config.viewMode, scaleMode = config.scaleMode,\n            barOrientation = config.barOrientation || 'horizontal',\n            barStacked = Boolean(config.barStacked),\n            curCty = i18n.allCountries, curY = null, curQ = null;\n        let periodYears = [];\n        let periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n        let periodYearQuarterMap = {};<\/p>\n<p>        let sparklines = [];\n        const hiddenLegendKeys = new Set();\n        const controls = {\n            periodsWrap: root.querySelector('.dashd-periods-wrap'),\n            yearButtonsBox: root.querySelector('.dashd-year-btns'),\n            quarterButtonsBox: root.querySelector('.dashd-q-btns'),\n            desktopViewToggle: root.querySelector('.dashd-toggle-view'),\n            desktopScaleToggle: root.querySelector('.dashd-toggle-scale'),\n            desktopOrientationToggle: root.querySelector('.dashd-toggle-orientation'),\n            desktopStackedToggle: root.querySelector('.dashd-toggle-stacked'),\n            mobileViewSelect: root.querySelector('.dashd-mobile-view'),\n            mobileScaleSelect: root.querySelector('.dashd-mobile-scale'),\n            mobileOrientationSelect: root.querySelector('.dashd-mobile-orientation'),\n            mobileStackedSelect: root.querySelector('.dashd-mobile-stacked'),\n            mobileYearSelect: root.querySelector('.dashd-mobile-year'),\n            mobileQuarterSelect: root.querySelector('.dashd-mobile-quarter'),\n            mobileFieldView: root.querySelector('.dashd-mobile-field-view'),\n            mobileFieldScale: root.querySelector('.dashd-mobile-field-scale'),\n            mobileFieldOrientation: root.querySelector('.dashd-mobile-field-orientation'),\n            mobileFieldStacked: root.querySelector('.dashd-mobile-field-stacked'),\n            mobileFieldYear: root.querySelector('.dashd-mobile-field-year'),\n            mobileFieldQuarter: root.querySelector('.dashd-mobile-field-quarter'),\n            mobileControlsWrap: root.querySelector('.dashd-mobile-controls')\n        };<\/p>\n<p>        const getAvailableQuartersForYear = (year) => {\n            const y = String(year ?? '');\n            if (!y || !periodYearQuarterMap || typeof periodYearQuarterMap !== 'object') {\n                return periodQuarters.slice();\n            }\n            const available = Array.isArray(periodYearQuarterMap[y])\n                ? periodYearQuarterMap[y].map((q) => String(q || '').toUpperCase()).filter(Boolean)\n                : [];\n            const normalized = periodQuarters.filter((q) => available.includes(q));\n            return normalized.length ? normalized : periodQuarters.slice();\n        };<\/p>\n<p>        const ensureValidQuarterForYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            if (!available.length) {\n                curQ = null;\n                return;\n            }\n            const current = String(curQ ?? '').toUpperCase();\n            if (!current || !available.includes(current)) {\n                curQ = available[0];\n            }\n        };<\/p>\n<p>        const renderQuarterControlsForCurrentYear = () => {\n            const available = getAvailableQuartersForYear(curY);\n            const qBox = controls.quarterButtonsBox;\n            if (qBox) {\n                qBox.innerHTML = periodQuarters.map((q) => {\n                    const isAvailable = available.includes(q);\n                    const isActive = String(q) === String(curQ);\n                    return `<button class=\"dashd-ui-btn ${isActive ? 'active-btn' : ''}\" data-v=\"${escapeHtml(q)}\"${isAvailable ? '' : ' disabled aria-disabled=\"true\" style=\"opacity:.45;cursor:not-allowed;\"'}>${escapeHtml(q)}<\/button>`;\n                }).join('');\n                qBox.querySelectorAll('button').forEach((b) => {\n                    b.onclick = () => {\n                        const nextQuarter = String(b.dataset.v || '');\n                        if (!nextQuarter) return;\n                        const allowed = getAvailableQuartersForYear(curY);\n                        if (!allowed.includes(nextQuarter)) return;\n                        curQ = nextQuarter;\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        loadData();\n                    };\n                });\n            }<\/p>\n<p>            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.innerHTML = available\n                    .map((q) => `<option value=\"${escapeHtml(q)}\">${escapeHtml(q)}<\/option>`)\n                    .join('');\n            }\n        };<\/p>\n<p>        const loader = root.querySelector('.dashd-loader-overlay');\n        const showLoader = () => { if (loader) { loader.style.display = 'flex'; setTimeout(() => loader.style.opacity = '1', 10); } };\n        const hideLoader = () => { if (loader) { loader.style.opacity = '0'; setTimeout(() => loader.style.display = 'none', 300); } };<\/p>\n<p>        const formatNum = (value) => {\n            if (value === null || value === undefined) return '';\n            const locale = config.lang === 'en' ? 'en-US' : 'ru-RU';\n            return new Intl.NumberFormat(locale).format(Number(value)); \n        };<\/p>\n<p>        const escapeHtml = (value) => String(value ?? '')\n            .replace(\/&\/g, '&amp;')\n            .replace(\/<\/g, '&lt;')\n            .replace(\/>\/g, '&gt;')\n            .replace(\/\"\/g, '&quot;')\n            .replace(\/'\/g, '&#039;');<\/p>\n<p>        const normalizeCountryName = (value) => String(value ?? '')\n            .toLowerCase()\n            .replace(\/\\s+\/g, ' ')\n            .trim();<\/p>\n<p>        const preferredCountryOrder = Array.isArray(config.countryOrder)\n            ? config.countryOrder.map((name) => String(name ?? '').trim()).filter(Boolean)\n            : [];\n        const preferredCountryOrderMap = new Map(\n            preferredCountryOrder.map((name, index) => [normalizeCountryName(name), index])\n        );<\/p>\n<p>        const sortCountriesByPreference = (countries) => {\n            if (!Array.isArray(countries)) return [];\n            if (!preferredCountryOrderMap.size) return countries.slice();<\/p>\n<p>            return countries.slice().sort((a, b) => {\n                const nameA = String(a ?? '');\n                const nameB = String(b ?? '');\n                const keyA = normalizeCountryName(nameA);\n                const keyB = normalizeCountryName(nameB);\n                const posA = preferredCountryOrderMap.has(keyA) ? preferredCountryOrderMap.get(keyA) : Number.POSITIVE_INFINITY;\n                const posB = preferredCountryOrderMap.has(keyB) ? preferredCountryOrderMap.get(keyB) : Number.POSITIVE_INFINITY;<\/p>\n<p>                if (posA !== posB) return posA - posB;\n                return nameA.localeCompare(nameB, undefined, { sensitivity: 'base' });\n            });\n        };<\/p>\n<p>        const countryColorMap = new Map();\n        const hashString = (value) => {\n            const input = String(value ?? '').toLowerCase().trim();\n            let hash = 0;\n            for (let i = 0; i < input.length; i++) {\n                hash = ((hash << 5) - hash) + input.charCodeAt(i);\n                hash |= 0;\n            }\n            return Math.abs(hash);\n        };\n        const getCountryColor = (countryName, fallbackIndex = 0) => {\n            const palette = Array.isArray(config.colors) ? config.colors : [];\n            if (!palette.length) return '#1e87f0';<\/p>\n<p>            const key = String(countryName ?? '').trim();\n            if (key === '') {\n                return (palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            }\n            if (countryColorMap.has(key)) {\n                return countryColorMap.get(key);\n            }<\/p>\n<p>            let index = hashString(key) % palette.length;\n            if (palette.length > countryColorMap.size) {\n                const used = new Set(Array.from(countryColorMap.values()));\n                let guard = 0;\n                while (used.has((palette[index] || '').trim()) && guard < palette.length) {\n                    index = (index + 1) % palette.length;\n                    guard++;\n                }\n            }\n\n            const color = (palette[index] || palette[Math.abs(fallbackIndex) % palette.length] || '#1e87f0').trim();\n            countryColorMap.set(key, color);\n            return color;\n        };\n\n        const BAR_RADIUS_BY_WIDTH_RATIO = 0.4;\n        const BAR_RADIUS_MIN = 2;\n        const BAR_RADIUS_MAX = 14;\n        const GROUPED_CATEGORY_PERCENTAGE = 0.74;\n        const GROUPED_BAR_PERCENTAGE = 0.86;\n\n        const getAdaptiveBarRadius = (ctx) => {\n            const chart = ctx?.chart;\n            const datasetIndex = Number(ctx?.datasetIndex ?? -1);\n            const dataIndex = Number(ctx?.dataIndex ?? -1);\n            if (!chart || datasetIndex < 0 || dataIndex < 0) {\n                return BAR_RADIUS_MIN;\n            }\n\n            const meta = chart.getDatasetMeta(datasetIndex);\n            const element = meta?.data?.[dataIndex];\n            if (!element) {\n                return BAR_RADIUS_MIN;\n            }\n\n            \/\/ Bind radius to the bar width (column thickness), not value length.\n            const indexAxis = String(chart?.options?.indexAxis || 'x');\n            const explicitWidth = indexAxis === 'y' ? Number(element.height) : Number(element.width);\n            const fallbackWidth = Math.min(\n                Number.isFinite(Number(element.width)) ? Number(element.width) : Number.POSITIVE_INFINITY,\n                Number.isFinite(Number(element.height)) ? Number(element.height) : Number.POSITIVE_INFINITY\n            );\n            const barWidth = Number.isFinite(explicitWidth) &#038;&#038; explicitWidth > 0\n                ? explicitWidth\n                : (Number.isFinite(fallbackWidth) && fallbackWidth > 0 ? fallbackWidth : 0);<\/p>\n<p>            if (!barWidth) {\n                return BAR_RADIUS_MIN;\n            }<\/p>\n<p>            const radius = barWidth * BAR_RADIUS_BY_WIDTH_RATIO;\n            return Math.max(BAR_RADIUS_MIN, Math.min(BAR_RADIUS_MAX, radius));\n        };<\/p>\n<p>        const getFullBarRadius = () => {\n            return (ctx) => {\n                const value = Number(ctx?.raw ?? 0);\n                if (!Number.isFinite(value) || value === 0) {\n                    return 0;\n                }\n                return getAdaptiveBarRadius(ctx);\n            };\n        };<\/p>\n<p>        const getStackSegmentRadius = (countryIndex, valuesByCountry, countries, orientation = 'horizontal') => {\n            return (ctx) => {\n                const pointIndex = Number(ctx?.dataIndex ?? -1);\n                if (pointIndex < 0) return 0;\n\n                const country = countries[countryIndex];\n                const current = Number(valuesByCountry[country]?.[pointIndex] ?? 0);\n                if (!Number.isFinite(current) || current === 0) {\n                    return 0;\n                }\n\n                let firstVisible = -1;\n                let lastVisible = -1;\n                for (let i = 0; i < countries.length; i++) {\n                    const cName = countries[i];\n                    const v = Number(valuesByCountry[cName]?.[pointIndex] ?? 0);\n                    if (!Number.isFinite(v) || v === 0) continue;\n                    if (firstVisible === -1) firstVisible = i;\n                    lastVisible = i;\n                }\n\n                if (firstVisible === -1) return 0;\n                const radius = getAdaptiveBarRadius(ctx);\n                if (firstVisible === lastVisible) return radius;\n                if (countryIndex === firstVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: 0, bottomLeft: radius, topRight: 0, bottomRight: radius }\n                        : { topLeft: radius, bottomLeft: radius, topRight: 0, bottomRight: 0 };\n                }\n                if (countryIndex === lastVisible) {\n                    return orientation === 'vertical'\n                        ? { topLeft: radius, bottomLeft: 0, topRight: radius, bottomRight: 0 }\n                        : { topLeft: 0, bottomLeft: 0, topRight: radius, bottomRight: radius };\n                }\n                return 0;\n            };\n        };\n\n        const getConfiguredIndicatorCount = () => {\n            const source = (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length)\n                ? config.indicatorSpecs\n                : (Array.isArray(config.indicatorIds) ? config.indicatorIds : []);\n            return new Set(source.map((v) => String(v ?? '').trim()).filter(Boolean)).size;\n        };<\/p>\n<p>        const isSingleIndicatorYearMode = () => (viewMode === 'bar' && getConfiguredIndicatorCount() === 1);\n        const syncWidgetTitle = () => {\n            const titleEl = root.querySelector('.dashd-widget-title');\n            if (!titleEl) return;<\/p>\n<p>            let title = String(titleEl.dataset.defaultTitle || i18n.analyticsOverview || 'Analytics Overview');\n            if (getConfiguredIndicatorCount() === 1) {\n                let source = null;\n                if (trendData && trendData.indicators) {\n                    source = trendData.indicators;\n                } else if (rawData && rawData.indicators) {\n                    source = rawData.indicators;\n                }\n                if (source) {\n                    const indicatorNames = Object.keys(source).filter(Boolean);\n                    if (indicatorNames.length === 1) {\n                        title = indicatorNames[0];\n                    }\n                }\n            }<\/p>\n<p>            titleEl.textContent = title;\n        };<\/p>\n<p>        const syncDesktopSelectors = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.type === viewMode);\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.scale === scaleMode);\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', el.dataset.orientation === barOrientation);\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.classList.toggle('active', String(el.dataset.stacked) === String(barStacked));\n            });\n        };<\/p>\n<p>        const syncPeriodButtons = () => {\n            if (controls.yearButtonsBox) {\n                controls.yearButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curY));\n                });\n            }\n            if (controls.quarterButtonsBox) {\n                controls.quarterButtonsBox.querySelectorAll('button').forEach((btn) => {\n                    btn.classList.toggle('active-btn', String(btn.dataset.v) === String(curQ));\n                });\n            }\n        };<\/p>\n<p>        const syncMobileSelectors = () => {\n            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.value = viewMode;\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.value = scaleMode;\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.value = barOrientation;\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.value = barStacked ? 'true' : 'false';\n            }\n            if (controls.mobileYearSelect && curY !== null) {\n                controls.mobileYearSelect.value = String(curY);\n            }\n            if (controls.mobileQuarterSelect && curQ !== null) {\n                controls.mobileQuarterSelect.value = String(curQ);\n            }\n        };<\/p>\n<p>        const syncPeriodControlVisibility = () => {\n            const hidePeriods = !Boolean(config.showPeriods) || (viewMode === 'line') || isSingleIndicatorYearMode();\n            const yearField = controls.mobileFieldYear;\n            const quarterField = controls.mobileFieldQuarter;<\/p>\n<p>            if (controls.periodsWrap) {\n                controls.periodsWrap.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (yearField) {\n                yearField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (quarterField) {\n                quarterField.style.display = hidePeriods ? 'none' : 'flex';\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.disabled = hidePeriods || controls.mobileYearSelect.options.length === 0;\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.disabled = hidePeriods || controls.mobileQuarterSelect.options.length === 0;\n            }<\/p>\n<p>            if (controls.desktopViewToggle) {\n                controls.desktopViewToggle.style.display = Boolean(config.showViewToggle) ? '' : 'none';\n            }\n            if (controls.desktopScaleToggle) {\n                controls.desktopScaleToggle.style.display = Boolean(config.showScaleToggle) ? '' : 'none';\n            }\n            if (controls.mobileFieldView) {\n                controls.mobileFieldView.style.display = Boolean(config.showViewToggle) ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldScale) {\n                controls.mobileFieldScale.style.display = Boolean(config.showScaleToggle) ? 'flex' : 'none';\n            }<\/p>\n<p>            const showBarControls = Boolean(config.showBarControlsUI) && viewMode === 'bar';\n            if (controls.desktopOrientationToggle) {\n                controls.desktopOrientationToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.desktopStackedToggle) {\n                controls.desktopStackedToggle.style.display = showBarControls ? '' : 'none';\n            }\n            if (controls.mobileFieldOrientation) {\n                controls.mobileFieldOrientation.style.display = showBarControls ? 'flex' : 'none';\n            }\n            if (controls.mobileFieldStacked) {\n                controls.mobileFieldStacked.style.display = showBarControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showDesktopControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || showBarControls;\n            const desktopControlsWrap = controls.desktopViewToggle ? controls.desktopViewToggle.parentNode : null;\n            if (desktopControlsWrap) {\n                desktopControlsWrap.style.display = showDesktopControls ? 'flex' : 'none';\n            }<\/p>\n<p>            const showMobileControls = Boolean(config.showViewToggle) || Boolean(config.showScaleToggle) || Boolean(config.showPeriods) || showBarControls;\n            if (controls.mobileControlsWrap) {\n                controls.mobileControlsWrap.style.display = showMobileControls ? '' : 'none';\n            }\n        };<\/p>\n<p>        const axisDict = { en: { k: 'Thousands', m: 'Millions', b: 'Billions' }, uk: { k: '\u0422\u0438\u0441\u044f\u0447\u0456', m: '\u041c\u0456\u043b\u044c\u0439\u043e\u043d\u0438', b: '\u041c\u0456\u043b\u044c\u044f\u0440\u0434\u0438' }, ru: { k: '\u0422\u044b\u0441\u044f\u0447\u0438', m: '\u041c\u0438\u043b\u043b\u0438\u043e\u043d\u044b', b: '\u041c\u0438\u043b\u043b\u0438\u0430\u0440\u0434\u044b' }, hy: { k: '\u0540\u0561\u0566\u0561\u0580\u0576\u0565\u0580', m: '\u0544\u056b\u056c\u056b\u0578\u0576\u0576\u0565\u0580', b: '\u0544\u056b\u056c\u056b\u0561\u0580\u0564\u0576\u0565\u0580' }, ro: { k: 'Mii', m: 'Milioane', b: 'Miliarde' }, ka: { k: '\u10d0\u10d7\u10d0\u10e1\u10d4\u10d1\u10d8', m: '\u10db\u10d8\u10da\u10d8\u10dd\u10dc\u10d4\u10d1\u10d8', b: '\u10db\u10d8\u10da\u10d8\u10d0\u10e0\u10d3\u10d4\u10d1\u10d8' } };<\/p>\n<p>        const wrapAxisLabel = (rawValue) => {\n            const text = String(rawValue ?? '').replace(\/\\s+\/g, ' ').trim();\n            if (!text) return '';<\/p>\n<p>            const isMobile = window.matchMedia('(max-width: 640px) and (orientation: portrait)').matches;\n            const maxCharsPerLine = isMobile ? 16 : 28;\n            const maxLines = 3;<\/p>\n<p>            const words = text.split(' ');\n            const lines = [];\n            let current = '';<\/p>\n<p>            for (let i = 0; i < words.length; i++) {\n                const word = words[i];\n                const candidate = current ? `${current} ${word}` : word;\n                if (candidate.length <= maxCharsPerLine) {\n                    current = candidate;\n                    continue;\n                }\n\n                if (current) {\n                    lines.push(current);\n                    current = '';\n                }\n\n                if (word.length <= maxCharsPerLine) {\n                    current = word;\n                } else {\n                    \/\/ Hard-wrap single oversized token.\n                    let rest = word;\n                    while (rest.length > maxCharsPerLine) {\n                        lines.push(rest.slice(0, maxCharsPerLine - 1) + '\u2026');\n                        rest = rest.slice(maxCharsPerLine - 1);\n                        if (lines.length >= maxLines) break;\n                    }\n                    if (lines.length >= maxLines) break;\n                    current = rest;\n                }<\/p>\n<p>                if (lines.length >= maxLines) break;\n            }<\/p>\n<p>            if (current && lines.length < maxLines) {\n                lines.push(current);\n            }\n\n            if (lines.length === 1) {\n                return lines[0];\n            }\n\n            if (lines.length > maxLines) {\n                return lines.slice(0, maxLines);\n            }<\/p>\n<p>            return lines;\n        };<\/p>\n<p>        const loadData = async () => {\n            showLoader();\n            syncPeriodControlVisibility();<\/p>\n<p>            let url = `${config.ajax}?action=get_dashd_modern_data&key=${config.key}&lang=${config.lang}`;\n            if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n            } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                url += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n            }\n            if (viewMode === 'line' || isSingleIndicatorYearMode()) {\n                url += '&all=true';\n            } else {\n                if (curY && curQ) url += `&year=${curY}&q=${curQ}`;\n            }<\/p>\n<p>            try {\n                const res = await fetch(url);\n                if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);<\/p>\n<p>                const json = await res.json();<\/p>\n<p>                if (json.success) {\n                    if (json.data && Array.isArray(json.data.countries)) {\n                        json.data.countries = sortCountriesByPreference(json.data.countries);\n                    }\n                    if (viewMode === 'line' || isSingleIndicatorYearMode()) trendData = json.data; else rawData = json.data;\n                    if (json.data.year) curY = json.data.year;\n                    if (json.data.quarter) curQ = json.data.quarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    const syncDiv = root.querySelector('.dashd-last-sync-time');\n                    if (syncDiv && json.data.last_sync) syncDiv.innerText = `${i18n.lastUpdated} ` + json.data.last_sync;\n                    render();\n                } else {\n                    console.error(\"DashD API Error:\", json);\n                    hideLoader();\n                }\n            } catch (error) {\n                console.error(\"DashD Network\/Parse Error in loadData:\", error);\n                hideLoader();\n            }\n        };<\/p>\n<p>        const getLineDataForCountry = (indName) => {\n            let historyData = new Array(trendData.periods.length).fill(0);\n            if (curCty === i18n.allCountries) {\n                trendData.countries.forEach(c => {\n                    if (trendData.indicators[indName][c]) {\n                        trendData.indicators[indName][c].forEach((val, idx) => { historyData[idx] += val; });\n                    }\n                });\n            } else {\n                if (trendData.indicators[indName][curCty]) { historyData = trendData.indicators[indName][curCty]; }\n            }\n            return historyData;\n        };<\/p>\n<p>        const buildSingleIndicatorYearData = () => {\n            if (!trendData || !trendData.periods || !trendData.indicators) return null;<\/p>\n<p>            const indicatorNames = Object.keys(trendData.indicators || {});\n            if (indicatorNames.length !== 1) return null;\n            const indicatorName = indicatorNames[0];<\/p>\n<p>            const countries = Array.isArray(trendData.countries) ? trendData.countries : [];\n            const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n            if (!countries.length || !periods.length) return null;<\/p>\n<p>            const quarterRank = { Q1: 1, Q2: 2, Q3: 3, Q4: 4 };\n            const latestIndexByYear = new Map();\n            periods.forEach((periodLabel, idx) => {\n                const m = String(periodLabel || '').trim().match(\/^(Q[1-4])\\s+(\\d{4})$\/i);\n                if (!m) return;\n                const q = String(m[1] || '').toUpperCase();\n                const year = parseInt(String(m[2] || ''), 10);\n                if (!Number.isFinite(year) || year <= 0) return;\n\n                const rank = quarterRank[q] || 0;\n                const prev = latestIndexByYear.get(year);\n                if (!prev || rank > prev.rank || (rank === prev.rank && idx > prev.idx)) {\n                    latestIndexByYear.set(year, { idx, rank, quarter: q });\n                }\n            });<\/p>\n<p>            const yearsAsc = Array.from(latestIndexByYear.keys()).sort((a, b) => a - b);\n            if (!yearsAsc.length) return null;<\/p>\n<p>            const valuesByCountry = {};\n            countries.forEach((country) => {\n                const series = (trendData.indicators[indicatorName] && trendData.indicators[indicatorName][country])\n                    ? trendData.indicators[indicatorName][country]\n                    : [];\n                valuesByCountry[country] = yearsAsc.map((year) => {\n                    const ref = latestIndexByYear.get(year);\n                    const raw = ref ? Number(series[ref.idx] ?? 0) : 0;\n                    return Number.isFinite(raw) ? raw : 0;\n                });\n            });<\/p>\n<p>            const yearLabels = yearsAsc.map((year) => {\n                const ref = latestIndexByYear.get(year);\n                if (!ref) return String(year);\n                return ref.quarter === 'Q4' ? String(year) : `${year} (${ref.quarter})`;\n            });<\/p>\n<p>            return { indicatorName, yearsAsc, yearLabels, countries, valuesByCountry };\n        };<\/p>\n<p>        const renderChart = () => {\n            if (typeof Chart === 'undefined') {\n                hideLoader();\n                return;\n            }\n            if (chart) chart.destroy();\n            const canvas = root.querySelector('.dashd-canvas');\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            let d = { labels: [], datasets: [] };<\/p>\n<p>            let maxVal = 0; let y1Max = 0; let useSecondaryAxis = false;\n            const isStackedBar = (viewMode === 'bar' && curCty === i18n.allCountries && barStacked);\n            const isYearMode = isSingleIndicatorYearMode();\n            const isHorizontalYearLayout = isYearMode && barOrientation === 'horizontal';\n            const barIndexAxis = viewMode === 'bar'\n                ? (isYearMode ? (isHorizontalYearLayout ? 'x' : 'y') : (barOrientation === 'vertical' ? 'x' : 'y'))\n                : 'x';\n            const isBarVertical = (viewMode === 'bar' && barIndexAxis === 'x');\n            const stackedSegmentOrientation = isBarVertical ? 'vertical' : 'horizontal';\n            const reverseCategoryAxis = (viewMode === 'bar' && isYearMode && barOrientation === 'vertical');<\/p>\n<p>            if (viewMode === 'line' && trendData) {\n                d.labels = trendData.periods;\n                const lineMetas = Object.keys(trendData.indicators).map((ind, idx) => {\n                    const hData = getLineDataForCountry(ind);\n                    const dsMax = Math.max(...hData.map(v => Math.abs(Number(v) || 0)));\n                    return { ind, idx, hData, dsMax };\n                });<\/p>\n<p>                const secondarySet = new Set();\n                const positiveMetas = lineMetas.filter(m => m.dsMax > 0);<\/p>\n<p>                \/\/ Stable axis assignment for many line series:\n                \/\/ split by the largest gap in order-of-magnitude, so similar datasets share one scale.\n                if (lineMetas.length > 3 && positiveMetas.length >= 2) {\n                    const sorted = [...positiveMetas].sort((a, b) => {\n                        if (a.dsMax === b.dsMax) {\n                            return String(a.ind).localeCompare(String(b.ind));\n                        }\n                        return a.dsMax - b.dsMax;\n                    });<\/p>\n<p>                    const minMax = sorted[0].dsMax;\n                    const maxMax = sorted[sorted.length - 1].dsMax;\n                    const spreadRatio = minMax > 0 ? (maxMax \/ minMax) : 1;<\/p>\n<p>                    let bestGap = 0;\n                    let bestSplitIdx = -1;\n                    for (let i = 0; i < sorted.length - 1; i++) {\n                        const cur = Math.log10(Math.max(sorted[i].dsMax, 1e-12));\n                        const next = Math.log10(Math.max(sorted[i + 1].dsMax, 1e-12));\n                        const gap = next - cur;\n                        if (gap > bestGap) {\n                            bestGap = gap;\n                            bestSplitIdx = i;\n                        }\n                    }<\/p>\n<p>                    const shouldSplit = spreadRatio >= 20 && bestGap >= 0.6 && bestSplitIdx >= 0;\n                    if (shouldSplit) {\n                        const lowCluster = sorted.slice(0, bestSplitIdx + 1);\n                        const highCluster = sorted.slice(bestSplitIdx + 1);\n                        if (lowCluster.length > 0 && highCluster.length > 0) {\n                            lowCluster.forEach(m => secondarySet.add(m.ind));\n                        }\n                    }\n                }<\/p>\n<p>                useSecondaryAxis = secondarySet.size > 0;<\/p>\n<p>                lineMetas.forEach((meta) => {\n                    const onSecondary = secondarySet.has(meta.ind);\n                    if (onSecondary) {\n                        if (meta.dsMax > y1Max) y1Max = meta.dsMax;\n                    } else {\n                        if (meta.dsMax > maxVal) maxVal = meta.dsMax;\n                    }<\/p>\n<p>                    const colorHex = config.colors[meta.idx % config.colors.length].trim();\n                    const bgColor = (colorHex.length === 7) ? colorHex + '66' : colorHex;<\/p>\n<p>                    d.datasets.push({\n                        label: meta.ind,\n                        data: meta.hData,\n                        borderColor: colorHex,\n                        backgroundColor: bgColor,\n                        borderWidth: config.weight,\n                        fill: true,\n                        tension: 0.3,\n                        yAxisID: onSecondary ? 'y1' : 'y'\n                    });\n                });\n            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (annual) {\n                    d.labels = annual.yearLabels && annual.yearLabels.length\n                        ? annual.yearLabels\n                        : annual.yearsAsc.map((y) => String(y));\n                    const isStackedYear = (curCty === i18n.allCountries && barStacked);<\/p>\n<p>                    if (isStackedYear) {\n                        annual.yearsAsc.forEach((_, yearIdx) => {\n                            let sum = 0;\n                            annual.countries.forEach((country) => {\n                                sum += Number(annual.valuesByCountry[country]?.[yearIdx] || 0);\n                            });\n                            if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                        });<\/p>\n<p>                        annual.countries.forEach((country, countryIdx) => {\n                            d.datasets.push({\n                                label: country,\n                                data: annual.valuesByCountry[country] || [],\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getStackSegmentRadius(countryIdx, annual.valuesByCountry, annual.countries, stackedSegmentOrientation),\n                                borderSkipped: false\n                            });\n                        });\n                    } else if (curCty === i18n.allCountries) {\n                        annual.countries.forEach((country, countryIdx) => {\n                            const vals = annual.valuesByCountry[country] || annual.yearsAsc.map(() => 0);\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = annual.valuesByCountry[curCty] || annual.yearsAsc.map(() => 0);\n                        vals.forEach((v) => {\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                        });\n                        d.datasets.push({\n                            label: curCty,\n                            data: vals,\n                            backgroundColor: getCountryColor(curCty, 0),\n                            borderRadius: getFullBarRadius(),\n                            borderSkipped: false\n                        });\n                    }\n                }\n            } else if (rawData && rawData.indicators) {\n                const inds = Object.keys(rawData.indicators);\n                d.labels = inds;<\/p>\n<p>                if (isStackedBar) {\n                    inds.forEach(ind => {\n                        let sum = 0;\n                        rawData.countries.forEach(c => sum += (rawData.indicators[ind][c] || 0));\n                        if (Math.abs(sum) > maxVal) maxVal = Math.abs(sum);\n                    });<\/p>\n<p>                    const stackedValuesByCountry = {};\n                    rawData.countries.forEach((countryName) => {\n                        stackedValuesByCountry[countryName] = inds.map((ind) => Number(rawData.indicators[ind]?.[countryName] || 0));\n                    });<\/p>\n<p>                    rawData.countries.forEach((c, i) => {\n                        const vals = inds.map(ind => rawData.indicators[ind][c] || 0);\n                        d.datasets.push({\n                            label: c,\n                            data: vals,\n                            backgroundColor: getCountryColor(c, i),\n                            borderRadius: getStackSegmentRadius(i, stackedValuesByCountry, rawData.countries, stackedSegmentOrientation),\n                            borderSkipped: false\n                        });\n                    });\n                } else {\n                    const isGroupedCountryBars = (viewMode === 'bar' && curCty === i18n.allCountries);\n                    if (isGroupedCountryBars) {\n                        rawData.countries.forEach((country, countryIdx) => {\n                            const vals = inds.map((ind) => Number(rawData.indicators[ind]?.[country] || 0));\n                            vals.forEach((v) => {\n                                if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            });\n                            d.datasets.push({\n                                label: country,\n                                data: vals,\n                                backgroundColor: getCountryColor(country, countryIdx),\n                                borderRadius: getFullBarRadius(),\n                                borderSkipped: false,\n                                categoryPercentage: GROUPED_CATEGORY_PERCENTAGE,\n                                barPercentage: GROUPED_BAR_PERCENTAGE\n                            });\n                        });\n                    } else {\n                        const vals = inds.map((i) => {\n                            const v = curCty === i18n.allCountries\n                                ? Object.values(rawData.indicators[i]).reduce((a, b) => a + b, 0)\n                                : (rawData.indicators[i][curCty] || 0);\n                            if (Math.abs(v) > maxVal) maxVal = Math.abs(v);\n                            return v;\n                        });\n                        const bgColor = (viewMode === 'bar' && curCty !== i18n.allCountries)\n                            ? getCountryColor(curCty, 0)\n                            : config.colors;\n                        const barDataset = { label: curCty, data: vals, backgroundColor: bgColor };\n                        if (viewMode === 'bar') {\n                            barDataset.borderRadius = getFullBarRadius();\n                            barDataset.borderSkipped = false;\n                        }\n                        d.datasets.push(barDataset);\n                    }\n                }\n            }<\/p>\n<p>            d.datasets = d.datasets.map((dataset, datasetIndex) => {\n                const labelPart = (typeof dataset.label === 'string' && dataset.label !== '') ? dataset.label : String(datasetIndex);\n                const legendKey = `${viewMode}|${curCty}|${labelPart}`;\n                return {\n                    ...dataset,\n                    _dashdLegendKey: legendKey,\n                    hidden: hiddenLegendKeys.has(legendKey)\n                };\n            });<\/p>\n<p>            const locUnits = axisDict[config.lang] || axisDict['en'];\n            let unitText = '', div = 1;\n            if (maxVal >= 1e9) { unitText = locUnits.b; div = 1e9; }\n            else if (maxVal >= 1e6) { unitText = locUnits.m; div = 1e6; }\n            else if (maxVal >= 1e3) { unitText = locUnits.k; div = 1e3; }<\/p>\n<p>            const valueAxisConfig = { \n                type: scaleMode, stacked: isStackedBar,\n                title: { display: unitText !== '', text: unitText, font: { weight: 'bold', size: 13 }, color: Chart.defaults.color },\n                ticks: { callback: function(value) { return formatNum(value \/ div); } } \n            };<\/p>\n<p>            let y1Config = null;\n            if (useSecondaryAxis) {\n                let unitText1 = '', div1 = 1;\n                if (y1Max >= 1e9) { unitText1 = locUnits.b; div1 = 1e9; }\n                else if (y1Max >= 1e6) { unitText1 = locUnits.m; div1 = 1e6; }\n                else if (y1Max >= 1e3) { unitText1 = locUnits.k; div1 = 1e3; }<\/p>\n<p>                y1Config = {\n                    type: scaleMode, position: 'right', grid: { drawOnChartArea: false }, \n                    title: { display: unitText1 !== '', text: unitText1, font: { weight: 'bold', size: 12 }, color: Chart.defaults.color },\n                    ticks: { color: Chart.defaults.color, callback: function(value) { return formatNum(value \/ div1); } }\n                };\n            }<\/p>\n<p>            \/\/ 1. \u041f\u0420\u041e\u0412\u0415\u0420\u042f\u0415\u041c \u0422\u0415\u041c\u0423 \u041f\u0420\u042f\u041c\u041e \u041f\u0415\u0420\u0415\u0414 \u041e\u0422\u0420\u0418\u0421\u041e\u0412\u041a\u041e\u0419\n            const isDark = document.documentElement.classList.contains('wp-dark-mode-active') || document.body.classList.contains('wp-dark-mode-active');\n            const textColor = isDark ? '#94a3b8' : '#666';\n            const gridColor = isDark ? '#334155' : '#e5e5e5';<\/p>\n<p>            \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0446\u0432\u0435\u0442\u0430 \u0442\u0435\u043c\u044b \u043a \u043d\u0430\u0448\u0438\u043c \u0443\u043c\u043d\u044b\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c \u043e\u0441\u0435\u0439\n            valueAxisConfig.grid = { color: gridColor };\n            valueAxisConfig.title.color = textColor;\n            valueAxisConfig.ticks.color = textColor;<\/p>\n<p>            if (y1Config) {\n                y1Config.grid.color = gridColor;\n                y1Config.title.color = textColor;\n                y1Config.ticks.color = textColor;\n            }<\/p>\n<p>            const categoryAxisConfig = {\n                stacked: isStackedBar,\n                reverse: reverseCategoryAxis,\n                grid: { color: gridColor },\n                ticks: {\n                    color: textColor,\n                    autoSkip: true,\n                    callback: function(value) {\n                        const label = (this && typeof this.getLabelForValue === 'function')\n                            ? this.getLabelForValue(value)\n                            : value;\n                        return wrapAxisLabel(label);\n                    }\n                }\n            };<\/p>\n<p>            \/\/ 2. \u0418\u041d\u0418\u0426\u0418\u0410\u041b\u0418\u0417\u0418\u0420\u0423\u0415\u041c \u0413\u0420\u0410\u0424\u0418\u041a \u0421 \u0423\u0427\u0415\u0422\u041e\u041c \u0412\u0421\u0415\u0425 \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041a (LIN\/LOG, \u0422\u042b\u0421\u042f\u0427\u0418\/\u041c\u0418\u041b\u041b\u0418\u041e\u041d\u042b \u0418 \u0422\u0415\u041c\u0410)\n            chart = new Chart(ctx, {\n                type: viewMode === 'line' ? 'line' : (viewMode === 'donut' ? 'doughnut' : 'bar'),\n                data: d,\n                options: { \n                    responsive: true, \n                    maintainAspectRatio: false, \n                    indexAxis: viewMode === 'bar' ? barIndexAxis : 'x', \n                    animation: { onComplete: hideLoader },\n                    color: textColor,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                color: textColor,\n                                usePointStyle: true,\n                                pointStyle: 'circle',\n                                boxWidth: 10,\n                                boxHeight: 10,\n                                generateLabels: function(chartInstance) {\n                                    const baseGenerator = Chart.defaults.plugins.legend.labels.generateLabels;\n                                    const items = typeof baseGenerator === 'function' ? baseGenerator(chartInstance) : [];\n                                    return items.map((item) => {\n                                        const ds = chartInstance && chartInstance.data && chartInstance.data.datasets\n                                            ? chartInstance.data.datasets[item.datasetIndex]\n                                            : null;\n                                        if (viewMode === 'line' && ds && ds.yAxisID === 'y1') {\n                                            item.text = `${item.text} [Right]`;\n                                        }\n                                        return item;\n                                    });\n                                }\n                            },\n                            onClick: (event, legendItem, legend) => {\n                                const chartInstance = legend.chart;\n                                const datasetIndex = legendItem.datasetIndex;\n                                if (typeof datasetIndex !== 'number') return;<\/p>\n<p>                                const dataset = chartInstance.data.datasets[datasetIndex];\n                                if (!dataset) return;<\/p>\n<p>                                const legendKey = dataset._dashdLegendKey || `${viewMode}|${curCty}|${dataset.label || datasetIndex}`;\n                                const shouldShow = !chartInstance.isDatasetVisible(datasetIndex);<\/p>\n<p>                                chartInstance.setDatasetVisibility(datasetIndex, shouldShow);\n                                if (shouldShow) hiddenLegendKeys.delete(legendKey);\n                                else hiddenLegendKeys.add(legendKey);<\/p>\n<p>                                chartInstance.update();\n                            }\n                        },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    let label = context.dataset.label || '';\n                                    if (label) label += ': ';\n                                    label += formatNum(context.raw); \n                                    return label;\n                                }\n                            }\n                        }\n                    },\n                    scales: viewMode !== 'donut' ? (viewMode === 'bar'\n                        ? (isBarVertical\n                            ? { x: categoryAxisConfig, y: valueAxisConfig }\n                            : { x: valueAxisConfig, y: categoryAxisConfig })\n                        : {\n                            x: categoryAxisConfig,\n                            y: valueAxisConfig,\n                            ...(useSecondaryAxis ? { y1: y1Config } : {})\n                        }) : {}\n                }\n            });            <\/p>\n<p>            \/\/ Fallback: never leave transparent loader over canvas interactions.\n            setTimeout(hideLoader, 350);\n        };<\/p>\n<p>        const renderTable = () => {\n            const thead = root.querySelector('.dashd-thead');\n            const tbody = root.querySelector('.dashd-tbody');\n            if (!thead || !tbody) return;<\/p>\n<p>            sparklines.forEach(c => c.destroy()); sparklines = [];<\/p>\n<p>            if (viewMode === 'line' && trendData && trendData.periods) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + trendData.periods.map(p => `<\/p>\n<th>${escapeHtml(p)}<\/th>\n<p>`).join('') + `<\/p>\n<th style=\"width:120px;\">${escapeHtml(i18n.trend)}<\/th>\n<p>`;<\/p>\n<p>                tbody.innerHTML = Object.keys(trendData.indicators).map((ind, i) => {\n                    const historyData = getLineDataForCountry(ind); \n                    const cells = historyData.map((v, idx) => {\n                        let qoqHtml = '';\n                        if (idx > 0) {\n                            let prev = historyData[idx-1];\n                            if (prev !== 0) {\n                                let pct = ((v - prev) \/ Math.abs(prev)) * 100;\n                                let color = pct >= 0 ? '#10b981' : '#ef4444';\n                                let arrow = pct >= 0 ? '&#9650;' : '&#9660;'; \n                                let bg = pct >= 0 ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                                if (pct !== 0) {\n                                    qoqHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; background:${bg}; padding: 2px 5px; border-radius: 4px; display:inline-block; margin-top:4px; font-weight:600;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/div>\n<p>`;\n                                }\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(v)}<\/div>\n<p>${qoqHtml}<\/td>\n<p>`;\n                    }).join('');<\/p>\n<p>                    const color = config.colors[i % config.colors.length].trim();\n                    const indEsc = escapeHtml(ind);\n                    const colorEsc = escapeHtml(color);\n                    return `<\/p>\n<tr>\n<td><strong>${indEsc}<\/strong><\/td>\n<p>${cells}<\/p>\n<td>\n<div style=\"height:35px; width:120px; position:relative; margin: 0 auto;\"><canvas class=\"dashd-sparkline\" data-ind=\"${indEsc}\" data-color=\"${colorEsc}\" width=\"120\" height=\"35\" style=\"width:120px; height:35px; display:block;\"><\/canvas><\/div>\n<\/td>\n<\/tr>\n<p>`;\n                }).join('');<\/p>\n<p>                setTimeout(() => {\n                    root.querySelectorAll('.dashd-sparkline').forEach(canvas => {\n                        const ind = canvas.dataset.ind; const color = canvas.dataset.color; const hData = getLineDataForCountry(ind);\n                        const spChart = new Chart(canvas.getContext('2d'), {\n                            type: 'line',\n                            data: { labels: trendData.periods, datasets: [{ data: hData, borderColor: color, borderWidth: 2, tension: 0.3, pointRadius: 0, fill: true, backgroundColor: (color.length === 7) ? color + '33' : color }] },\n                            options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } }, scales: { x: { display: false }, y: { display: false, min: Math.min(...hData) * 0.9, max: Math.max(...hData) * 1.1 } }, animation: false }\n                        });\n                        sparklines.push(spChart);\n                    });\n                }, 50);<\/p>\n<p>            } else if (isSingleIndicatorYearMode() && trendData && trendData.indicators) {\n                const annual = buildSingleIndicatorYearData();\n                if (!annual) {\n                    thead.innerHTML = '';\n                    tbody.innerHTML = '';\n                    return;\n                }<\/p>\n<p>                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + annual.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = annual.yearsAsc.map((year, rowIdx) => {\n                    let rowSum = 0;\n                    const cells = annual.countries.map((country) => {\n                        const val = Number(annual.valuesByCountry[country]?.[rowIdx] || 0);\n                        rowSum += val;\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(val)}<\/div>\n<\/td>\n<p>`;\n                    }).join('');\n                    const periodLabel = (annual.yearLabels && annual.yearLabels[rowIdx]) ? annual.yearLabels[rowIdx] : String(year);\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(periodLabel)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            } else if (rawData && rawData.indicators) {\n                thead.innerHTML = `<\/p>\n<th>${escapeHtml(i18n.indicator)}<\/th>\n<p>` + rawData.countries.map(c => `<\/p>\n<th>${escapeHtml(c)}<\/th>\n<p>`).join('') + `<\/p>\n<th class=\"dashd-total-col\">${escapeHtml(i18n.total)}<\/th>\n<p>`;\n                tbody.innerHTML = Object.keys(rawData.indicators).map(ind => {\n                    let rowSum = 0;\n                    const cells = rawData.countries.map(c => {\n                        const cur = rawData.indicators[ind][c] || 0; rowSum += cur;<\/p>\n<p>                        let yoyHtml = '';\n                        if (rawData.previous && rawData.previous[ind] && rawData.previous[ind][c] !== undefined) {\n                            const prev = rawData.previous[ind][c];\n                            if (prev !== 0) {\n                                const diff = ((cur - prev) \/ Math.abs(prev)) * 100;\n                                const color = diff >= 0 ? '#10b981' : '#ef4444';\n                                const arrow = diff >= 0 ? '\u25b2' : '\u25bc';\n                                yoyHtml = `<\/p>\n<div style=\"font-size:10px; color:${color}; font-weight:700; margin-top:4px;\">${arrow} ${Math.abs(diff).toFixed(1)}% vs LY<\/div>\n<p>`;\n                            }\n                        }\n                        return `<\/p>\n<td>\n<div style=\"font-size:13px;\">${formatNum(cur)}<\/div>\n<p>${yoyHtml}<\/td>\n<p>`;\n                    }).join('');\n                    return `<\/p>\n<tr>\n<td><strong>${escapeHtml(ind)}<\/strong><\/td>\n<p>${cells}<\/p>\n<td class=\"dashd-total-col\">${formatNum(rowSum)}<\/td>\n<\/tr>\n<p>`;\n                }).join('');\n            }\n        };<\/p>\n<p>        const render = () => {\n            syncDesktopSelectors();\n            syncPeriodControlVisibility();\n            syncMobileSelectors();\n            syncWidgetTitle();\n            const cBox = root.querySelector('.dashd-country-btns'); let cList = [];\n            if ((viewMode === 'line' || isSingleIndicatorYearMode()) && trendData && trendData.countries) {\n                cList = trendData.countries;\n            } else if (viewMode !== 'line' && rawData && rawData.countries) {\n                cList = rawData.countries;\n            }\n            if (cBox && cList.length > 0) {\n                cBox.style.display = 'flex';\n                cBox.innerHTML = `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===i18n.allCountries?'active-btn':''}\">${escapeHtml(i18n.allCountries)}<\/button>`;\n                cList.forEach(c => { cBox.innerHTML += `<button class=\"dashd-ui-btn dashd-country-btn ${curCty===c?'active-btn':''}\">${escapeHtml(c)}<\/button>`; });\n                cBox.querySelectorAll('button').forEach(b => {\n                    b.onclick = () => { curCty = b.innerText; cBox.querySelectorAll('button').forEach(x => x.classList.remove('active-btn')); b.classList.add('active-btn'); renderChart(); renderTable(); };\n                });\n            } else if (cBox) { cBox.style.display = 'none'; }\n            renderChart(); renderTable();\n        };<\/p>\n<p>        const bindEvents = () => {\n            root.querySelectorAll('.dashd-toggle-view .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextMode = String(this.dataset.type || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-scale .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextScale = String(this.dataset.scale || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-orientation .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const nextOrientation = String(this.dataset.orientation || '');\n                    if (!nextOrientation || nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation === 'vertical' ? 'vertical' : 'horizontal';\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });\n            root.querySelectorAll('.dashd-toggle-stacked .dashd-selector-label').forEach((el) => {\n                el.onclick = function() {\n                    const next = String(this.dataset.stacked || '');\n                    const nextStacked = (next === 'true');\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            });<\/p>\n<p>            if (controls.mobileViewSelect) {\n                controls.mobileViewSelect.onchange = function() {\n                    const nextMode = String(this.value || '');\n                    if (!nextMode || nextMode === viewMode) return;\n                    viewMode = nextMode;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileScaleSelect) {\n                controls.mobileScaleSelect.onchange = function() {\n                    const nextScale = String(this.value || '');\n                    if (!nextScale || nextScale === scaleMode) return;\n                    scaleMode = nextScale;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileOrientationSelect) {\n                controls.mobileOrientationSelect.onchange = function() {\n                    const next = String(this.value || '');\n                    const nextOrientation = next === 'vertical' ? 'vertical' : 'horizontal';\n                    if (nextOrientation === barOrientation) return;\n                    barOrientation = nextOrientation;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileStackedSelect) {\n                controls.mobileStackedSelect.onchange = function() {\n                    const nextStacked = String(this.value || '') === 'true';\n                    if (nextStacked === barStacked) return;\n                    barStacked = nextStacked;\n                    syncDesktopSelectors();\n                    syncMobileSelectors();\n                    renderChart();\n                };\n            }\n            if (controls.mobileYearSelect) {\n                controls.mobileYearSelect.onchange = function() {\n                    const nextYear = String(this.value || '');\n                    if (!nextYear || nextYear === String(curY)) return;\n                    curY = nextYear;\n                    ensureValidQuarterForYear();\n                    renderQuarterControlsForCurrentYear();\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }\n            if (controls.mobileQuarterSelect) {\n                controls.mobileQuarterSelect.onchange = function() {\n                    const nextQuarter = String(this.value || '');\n                    if (!nextQuarter || nextQuarter === String(curQ)) return;\n                    const allowed = getAvailableQuartersForYear(curY);\n                    if (!allowed.includes(nextQuarter)) {\n                        ensureValidQuarterForYear();\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        return;\n                    }\n                    curQ = nextQuarter;\n                    syncPeriodButtons();\n                    syncMobileSelectors();\n                    loadData();\n                };\n            }<\/p>\n<p>            const toggleBtn = document.getElementById('toggle-dw_6a5a060e7a395');\n            if (toggleBtn) {\n                toggleBtn.onclick = function() {\n                    const tb = document.getElementById('tb-dw_6a5a060e7a395'); const ham = this.querySelector('.dashd-hamburger');\n                    if (tb.style.display === 'none') { tb.style.display = 'block'; ham.classList.add('open'); } else { tb.style.display = 'none'; ham.classList.remove('open'); }\n                };\n            }<\/p>\n<p>            const isGated = Boolean(config.isGated);\n            let pendingAction = null;\n            const modal = document.getElementById('gated-modal-dw_6a5a060e7a395');\n            const errorDiv = document.getElementById('gated-error-dw_6a5a060e7a395');\n            const emailInput = document.getElementById('gated-email-dw_6a5a060e7a395');\n            const hpInput = document.getElementById('gated-hp-dw_6a5a060e7a395');\n            const submitBtn = document.getElementById('gated-submit-dw_6a5a060e7a395');<\/p>\n<p>            const execCsv = () => {\n                let csv = []; const rows = root.querySelectorAll('.dashd-table tr'); let headerRow = [];\n                if (!rows.length || !rows[0]) {\n                    console.warn('DashD: CSV export aborted, table is empty.');\n                    return;\n                }\n                const headers = rows[0].querySelectorAll('th');\n                if (!headers.length) {\n                    console.warn('DashD: CSV export aborted, no headers found.');\n                    return;\n                }<\/p>\n<p>                const sanitizeCsvCell = (value) => {\n                    const raw = String(value ?? '').replace(\/\\u0000\/g, '');\n                    const trimmed = raw.trimStart();\n                    if (!trimmed) return raw;<\/p>\n<p>                    const normalizedNumeric = trimmed.replace(',', '.');\n                    const isNumericCell = \/^-?\\d+(\\.\\d+)?$\/.test(normalizedNumeric);\n                    if (isNumericCell) return raw;<\/p>\n<p>                    if (\/^[=+@]\/.test(trimmed) || \/^[\\t\\r\\n]\/.test(trimmed) || \/^-\/.test(trimmed)) {\n                        return `'${raw}`;\n                    }<\/p>\n<p>                    return raw;\n                };<\/p>\n<p>                for (let j = 0; j < headers.length; j++) {\n                    const cell = sanitizeCsvCell(headers[j].innerText.trim()).replace(\/\"\/g, '\"\"');\n                    headerRow.push('\"' + cell + '\"');\n                }\n                csv.push(headerRow.join(','));\n\n                for (let i = 1; i < rows.length; i++) {\n                    let row = [], cols = rows[i].querySelectorAll('td');\n                    for (let j = 0; j < cols.length; j++) {\n                        let textDiv = cols[j].querySelector('div');\n                        let data = textDiv ? textDiv.innerText : cols[j].innerText;\n                        if (j > 0) data = data.replace(\/\\s\/g, ''); \n                        data = sanitizeCsvCell(data).replace(\/\"\/g, '\"\"');\n                        row.push('\"' + data + '\"');\n                    }\n                    csv.push(row.join(','));\n                }\n                const blob = new Blob([\"\\uFEFF\" + csv.join('\\n')], { type: 'text\/csv;charset=utf-8;' });\n                const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `analytics_export_${new Date().toISOString().slice(0,10)}.csv`; link.click();\n            };<\/p>\n<p>            const execPdf = async (btn) => {\n                const originalHTML = btn.innerHTML;\n                btn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 2s linear infinite;\"><\/span> ${escapeHtml(i18n.wait)}`;<\/p>\n<p>                const waitForImages = async (scope) => {\n                    if (!scope) return;\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    if (!images.length) return;<\/p>\n<p>                    await Promise.all(images.map((img) => {\n                        if (img.complete && img.naturalWidth > 0) {\n                            return Promise.resolve();\n                        }\n                        return new Promise((resolve) => {\n                            let settled = false;\n                            const done = () => {\n                                if (settled) return;\n                                settled = true;\n                                resolve();\n                            };\n                            img.addEventListener('load', done, { once: true });\n                            img.addEventListener('error', done, { once: true });\n                            setTimeout(done, 2000);\n                        });\n                    }));\n                };<\/p>\n<p>                const prepareSvgImagesForCapture = async (scope) => {\n                    if (!scope) return [];\n                    const images = Array.from(scope.querySelectorAll('img'));\n                    const converted = [];\n                    if (!images.length) return converted;<\/p>\n<p>                    const isSvgImageSrc = (src) => {\n                        if (!src) return false;\n                        return \/^data:image\\\/svg\\+xml\/i.test(src) || \/\\.svg(?:[?#].*)?$\/i.test(src);\n                    };<\/p>\n<p>                    const convertImage = (img) => new Promise((resolve) => {\n                        const src = (img.getAttribute('src') || '').trim();\n                        if (!isSvgImageSrc(src)) {\n                            resolve();\n                            return;\n                        }<\/p>\n<p>                        const probe = new Image();\n                        probe.crossOrigin = 'anonymous';\n                        probe.decoding = 'sync';<\/p>\n<p>                        probe.onload = () => {\n                            try {\n                                const rect = img.getBoundingClientRect();\n                                const attrWidth = parseFloat(img.getAttribute('width') || '0');\n                                const attrHeight = parseFloat(img.getAttribute('height') || '0');\n                                const css = window.getComputedStyle(img);\n                                const cssWidth = parseFloat(css.width || '0');\n                                const cssHeight = parseFloat(css.height || '0');<\/p>\n<p>                                let width = probe.naturalWidth || Math.round(rect.width) || Math.round(cssWidth) || Math.round(attrWidth);\n                                let height = probe.naturalHeight || Math.round(rect.height) || Math.round(cssHeight) || Math.round(attrHeight);<\/p>\n<p>                                if ((!height || height < 2) &#038;&#038; width &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    height = Math.round(width * (probe.naturalHeight \/ probe.naturalWidth));\n                                }\n                                if ((!width || width < 2) &#038;&#038; height &#038;&#038; probe.naturalWidth > 0 && probe.naturalHeight > 0) {\n                                    width = Math.round(height * (probe.naturalWidth \/ probe.naturalHeight));\n                                }\n                                if (!width || width < 2) width = 400;\n                                if (!height || height < 2) height = Math.max(120, Math.round(width * 0.3));\n\n                                width = Math.max(1, Math.min(4096, Number(width) || 1));\n                                height = Math.max(1, Math.min(4096, Number(height) || 1));\n\n                                const canvas = document.createElement('canvas');\n                                canvas.width = width;\n                                canvas.height = height;\n\n                                const ctx2d = canvas.getContext('2d');\n                                if (!ctx2d) {\n                                    resolve();\n                                    return;\n                                }\n\n                                ctx2d.drawImage(probe, 0, 0, width, height);\n                                const pngData = canvas.toDataURL('image\/png');\n                                if (!pngData) {\n                                    resolve();\n                                    return;\n                                }\n\n                                img.dataset.dashdOrigSrc = src;\n                                img.src = pngData;\n                                converted.push(img);\n                            } catch (e) {\n                                \/\/ ignore and keep original SVG image\n                            }\n                            resolve();\n                        };\n\n                        probe.onerror = () => resolve();\n                        probe.src = src;\n                    });<\/p>\n<p>                    await Promise.all(images.map(convertImage));\n                    return converted;\n                };<\/p>\n<p>                const restoreConvertedSvgImages = (images) => {\n                    if (!Array.isArray(images) || !images.length) return;\n                    images.forEach((img) => {\n                        if (img && img.dataset && img.dataset.dashdOrigSrc) {\n                            img.src = img.dataset.dashdOrigSrc;\n                            delete img.dataset.dashdOrigSrc;\n                        }\n                    });\n                };<\/p>\n<p>                const prepareSparklineCanvasesForCapture = (scope) => {\n                    if (!scope) return [];\n                    const canvases = Array.from(scope.querySelectorAll('canvas.dashd-sparkline'));\n                    if (!canvases.length) return [];<\/p>\n<p>                    const state = [];\n                    canvases.forEach((canvas) => {\n                        const parent = canvas.parentNode;\n                        if (!parent) return;<\/p>\n<p>                        try {\n                            const dataUrl = canvas.toDataURL('image\/png');\n                            if (dataUrl && dataUrl !== 'data:,') {\n                                const img = document.createElement('img');\n                                img.src = dataUrl;\n                                img.alt = '';\n                                img.style.width = '100%';\n                                img.style.height = '100%';\n                                img.style.display = 'block';\n                                img.style.objectFit = 'contain';\n                                parent.replaceChild(img, canvas);\n                                state.push({ type: 'replaced', parent, canvas, img });\n                                return;\n                            }\n                        } catch (e) {\n                            \/\/ Tainted\/invalid canvas: ignore in html2canvas capture.\n                        }<\/p>\n<p>                        canvas.setAttribute('data-html2canvas-ignore', 'true');\n                        state.push({ type: 'ignored', canvas });\n                    });<\/p>\n<p>                    return state;\n                };<\/p>\n<p>                const restoreSparklineCanvasesAfterCapture = (state) => {\n                    if (!Array.isArray(state) || !state.length) return;\n                    state.forEach((entry) => {\n                        if (!entry || !entry.type) return;<\/p>\n<p>                        if (entry.type === 'replaced') {\n                            if (entry.parent && entry.img && entry.canvas && entry.img.parentNode === entry.parent) {\n                                entry.parent.replaceChild(entry.canvas, entry.img);\n                            }\n                        } else if (entry.type === 'ignored') {\n                            if (entry.canvas && entry.canvas.removeAttribute) {\n                                entry.canvas.removeAttribute('data-html2canvas-ignore');\n                            }\n                        }\n                    });\n                };<\/p>\n<p>                const buildLinePdfVerticalTable = () => {\n                    if (viewMode !== 'line' || !trendData || !trendData.periods || !trendData.indicators) {\n                        return null;\n                    }<\/p>\n<p>                    const periods = Array.isArray(trendData.periods) ? trendData.periods : [];\n                    const indicators = Object.keys(trendData.indicators || {});\n                    if (!periods.length || !indicators.length) return null;<\/p>\n<p>                    const cards = indicators.map((ind, idx) => {\n                        const rawSeries = getLineDataForCountry(ind);\n                        const series = Array.isArray(rawSeries) ? rawSeries : [];\n                        const color = (config.colors[idx % config.colors.length] || '#1e87f0').trim();<\/p>\n<p>                        const rows = periods.map((period, periodIndex) => {\n                            const curNum = Number(series[periodIndex] ?? 0);\n                            const curVal = Number.isFinite(curNum) ? curNum : 0;<\/p>\n<p>                            let trendHtml = '<span style=\"color:#94a3b8;\">-<\/span>';\n                            if (periodIndex > 0) {\n                                const prevNum = Number(series[periodIndex - 1] ?? 0);\n                                const prevVal = Number.isFinite(prevNum) ? prevNum : 0;\n                                if (prevVal !== 0) {\n                                    const pct = ((curVal - prevVal) \/ Math.abs(prevVal)) * 100;\n                                    if (Number.isFinite(pct) && pct !== 0) {\n                                        const isUp = pct >= 0;\n                                        const arrow = isUp ? '&#9650;' : '&#9660;';\n                                        const colorHex = isUp ? '#10b981' : '#ef4444';\n                                        trendHtml = `<span style=\"color:${colorHex}; font-weight:700;\">${arrow} ${Math.abs(pct).toFixed(1)}%<\/span>`;\n                                    }\n                                }\n                            }<\/p>\n<p>                            return `<\/p>\n<tr>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; color:#334155; font-size:12px;\">${escapeHtml(period)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; color:#0f172a; font-size:12px; font-weight:600;\">${formatNum(curVal)}<\/td>\n<td style=\"padding:8px 10px; border-bottom:1px solid #eef2f7; text-align:right; font-size:11px;\">${trendHtml}<\/td>\n<\/tr>\n<p>`;\n                        }).join('');<\/p>\n<p>                        return `<\/p>\n<div style=\"margin:0; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff; break-inside:avoid; page-break-inside:avoid;\">\n<div style=\"padding:10px 12px; background:#ffffff; border-left:4px solid ${escapeHtml(color)}; font-size:13px; font-weight:700; color:#0f172a;\">\n                                ${escapeHtml(ind)}\n                            <\/div>\n<table style=\"width:100%; border-collapse:collapse; table-layout:fixed;\">\n<thead>\n<tr>\n<th style=\"padding:8px 10px; text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Period<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">Value<\/th>\n<th style=\"padding:8px 10px; text-align:right; font-size:11px; text-transform:uppercase; letter-spacing:.02em; color:#475569; background:#f8fafc; border-bottom:1px solid #e2e8f0;\">QoQ<\/th>\n<\/tr>\n<\/thead>\n<tbody>${rows}<\/tbody>\n<\/table><\/div>\n<p>`;\n                    });<\/p>\n<p>                    const container = document.createElement('div');\n                    container.className = 'dashd-temp-pdf-line-vertical uk-margin-top';\n                    container.innerHTML = `<\/p>\n<div style=\"margin-top:15px; border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; background:#fff;\">\n<div style=\"padding:10px 12px; background:#f8fafc; border-bottom:1px solid #e2e8f0; font-size:13px; font-weight:700; color:#334155;\">\n                            Line Data (Full Table View)\n                        <\/div>\n<div style=\"padding:10px;\">\n<div style=\"display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; align-items:start;\">\n                                ${cards.join('')}\n                            <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>`;\n                    return container;\n                };<\/p>\n<p>                const wm = root.querySelector('.dashd-pdf-watermark'); \n                const header = root.querySelector('.dashd-pdf-header'); \n                const footer = root.querySelector('.dashd-pdf-footer');\n                const tableWrapper = root.querySelector('.dashd-table-wrapper');\n                const tableScroll = root.querySelector('.dashd-table-scroll-container');\n                let convertedSvgImages = [];\n                let sparklineCanvasState = [];\n                let tempLinePdfTable = null;\n                const isLinePdfMode = viewMode === 'line';<\/p>\n<p>                const viewToggleNode = root.querySelector('.dashd-toggle-view');\n                const viewScaleToggles = viewToggleNode ? viewToggleNode.parentNode : null;\n                const pWrap = root.querySelector('.dashd-periods-wrap');\n                const cBox = root.querySelector('.dashd-country-btns');<\/p>\n<p>                const origViewScaleDisplay = viewScaleToggles ? viewScaleToggles.style.display : '';\n                const origPWrapDisplay = pWrap ? pWrap.style.display : '';\n                const origCBoxDisplay = cBox ? cBox.style.display : '';\n                const origTableDisplay = tableWrapper ? tableWrapper.style.display : '';\n                const origScrollOverflow = tableScroll ? tableScroll.style.overflow : '';\n                const origScrollMaxHeight = tableScroll ? tableScroll.style.maxHeight : '';<\/p>\n<p>                if (viewScaleToggles) viewScaleToggles.style.display = 'none';\n                if (pWrap) pWrap.style.display = 'none';\n                if (cBox) cBox.style.display = 'none';<\/p>\n<p>                if (viewMode !== 'line' && pWrap) {\n                    const tempPeriodLabel = document.createElement('div');\n                    tempPeriodLabel.className = 'dashd-temp-pdf-label';\n                    tempPeriodLabel.innerHTML = `<\/p>\n<div style=\"font-size: 15px; font-weight: 700; color: #334155; background: #f8fafc; padding: 6px 18px; border-radius: 8px; border: 1px solid #e2e8f0; margin-right: 20px; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.05);\">${escapeHtml(curY)} <span style=\"color: #94a3b8; font-weight: 400;\">&nbsp;\/&nbsp;<\/span> ${escapeHtml(curQ)}<\/div>\n<p>`;\n                    pWrap.parentNode.insertBefore(tempPeriodLabel, pWrap.nextSibling);\n                }<\/p>\n<p>                if (cBox) {\n                    const tempCountryLabel = document.createElement('div');\n                    tempCountryLabel.className = 'dashd-temp-pdf-label';\n                    tempCountryLabel.innerHTML = `<\/p>\n<div style=\"font-size: 14px; font-weight: 600; color: #fff; background-color: #1e87f0; padding: 4px 14px; border-radius: 20px; display: inline-block; margin-bottom: 15px;\">${escapeHtml(curCty)}<\/div>\n<p>`;\n                    cBox.parentNode.insertBefore(tempCountryLabel, cBox.nextSibling);\n                }<\/p>\n<p>                const now = new Date();\n                const dateStr = now.toLocaleDateString() + ' ' + now.toLocaleTimeString();\n                let origHeaderDisplay = '';\n                let origHeaderHtml = '';\n                let origHeaderJustify = '';\n                let origHeaderAlign = '';\n                let origHeaderTextAlign = '';<\/p>\n<p>                if (header) {\n                    origHeaderDisplay = header.style.display;\n                    origHeaderHtml = header.innerHTML;\n                    origHeaderJustify = header.style.justifyContent;\n                    origHeaderAlign = header.style.alignItems;\n                    origHeaderTextAlign = header.style.textAlign;<\/p>\n<p>                    header.style.display = 'flex';\n                    header.style.justifyContent = 'space-between';\n                    header.style.alignItems = 'center';\n                    header.style.textAlign = 'left';<\/p>\n<p>                    const headerTitle = document.createElement('div');\n                    headerTitle.innerHTML = `<\/p>\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<p>                    `;<\/p>\n<p>                    const logoWrap = document.createElement('div');\n                    while (header.firstChild) {\n                        logoWrap.appendChild(header.firstChild);\n                    }<\/p>\n<p>                    header.appendChild(headerTitle);\n                    header.appendChild(logoWrap);\n                } else {\n                    const tempHeader = document.createElement('div');\n                    tempHeader.className = 'dashd-temp-pdf-header';\n                    tempHeader.innerHTML = `<\/p>\n<div style=\"border-bottom: 2px solid #f0f0f1; padding-bottom: 15px; margin-bottom: 25px;\">\n<div style=\"font-size: 18px; font-weight: bold; color: #03045E; margin-bottom: 3px;\">EU4Business EBRD Credit Line - Analytics Report<\/div>\n<div style=\"font-size: 11px; color: #666;\">Generated on: ${escapeHtml(dateStr)}<\/div>\n<\/p><\/div>\n<p>                    `;\n                    root.insertBefore(tempHeader, root.firstChild);\n                }<\/p>\n<p>                if(wm) wm.style.display = 'block'; \n                if(footer) footer.style.display = 'block';\n                if(tableWrapper) tableWrapper.style.display = isLinePdfMode ? 'none' : 'block';\n                if(tableScroll && !isLinePdfMode) {\n                    tableScroll.style.overflow = 'visible';\n                    tableScroll.style.maxHeight = 'none';\n                }<\/p>\n<p>                if (isLinePdfMode) {\n                    tempLinePdfTable = buildLinePdfVerticalTable();\n                    if (tempLinePdfTable) {\n                        if (tableWrapper && tableWrapper.parentNode) {\n                            tableWrapper.parentNode.insertBefore(tempLinePdfTable, tableWrapper.nextSibling);\n                        } else {\n                            root.appendChild(tempLinePdfTable);\n                        }\n                    }\n                }<\/p>\n<p>                if (!isLinePdfMode) {\n                    \/\/ Re-render table now that it's visible so sparkline canvases can get proper dimensions.\n                    renderTable();\n                    await new Promise(r => setTimeout(r, 200));\n                }\n                convertedSvgImages = await prepareSvgImagesForCapture(root);\n                await waitForImages(root);\n                sparklineCanvasState = isLinePdfMode ? [] : prepareSparklineCanvasesForCapture(root);<\/p>\n<p>                const cleanupPdfDomState = () => {\n                    if(wm) wm.style.display = 'none';\n                    if(footer) footer.style.display = 'none';\n                    if (header) {\n                        header.style.display = origHeaderDisplay;\n                        header.innerHTML = origHeaderHtml;\n                        header.style.justifyContent = origHeaderJustify;\n                        header.style.alignItems = origHeaderAlign;\n                        header.style.textAlign = origHeaderTextAlign;\n                    } else {\n                        const tempH = root.querySelector('.dashd-temp-pdf-header');\n                        if (tempH) tempH.remove();\n                    }<\/p>\n<p>                    if (viewScaleToggles) viewScaleToggles.style.display = origViewScaleDisplay;\n                    if (pWrap) pWrap.style.display = origPWrapDisplay;\n                    if (cBox) cBox.style.display = origCBoxDisplay;\n                    root.querySelectorAll('.dashd-temp-pdf-label').forEach(el => el.remove());<\/p>\n<p>                    if (tempLinePdfTable && tempLinePdfTable.parentNode) {\n                        tempLinePdfTable.parentNode.removeChild(tempLinePdfTable);\n                    }<\/p>\n<p>                    if(tableWrapper) tableWrapper.style.display = origTableDisplay;\n                    if(tableScroll) {\n                        tableScroll.style.overflow = origScrollOverflow;\n                        tableScroll.style.maxHeight = origScrollMaxHeight;\n                    }\n                    restoreSparklineCanvasesAfterCapture(sparklineCanvasState);\n                    restoreConvertedSvgImages(convertedSvgImages);\n                };<\/p>\n<p>                try {\n                    const canvas = await html2canvas(root, { \n                        scale: 2, \n                        useCORS: true, \n                        backgroundColor: '#ffffff',\n                        windowWidth: root.scrollWidth,\n                        windowHeight: root.scrollHeight,\n                        ignoreElements: (el) => {\n                            if (!el || !el.tagName) return false;\n                            if (el.tagName.toLowerCase() === 'canvas' && el.classList && el.classList.contains('dashd-sparkline')) {\n                                return true;\n                            }\n                            return false;\n                        }\n                    });<\/p>\n<p>                    cleanupPdfDomState();<\/p>\n<p>                    const imgData = canvas.toDataURL('image\/jpeg', 1.0); \n                    const { jsPDF } = window.jspdf;<\/p>\n<p>                    const pdfWidth = 210;\n                    const pdfHeight = (canvas.height * pdfWidth) \/ canvas.width;<\/p>\n<p>                    const pdf = new jsPDF({\n                        orientation: pdfWidth > pdfHeight ? 'l' : 'p',\n                        unit: 'mm',\n                        format: [pdfWidth, pdfHeight]\n                    });<\/p>\n<p>                    pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight); \n                    pdf.save(`dashboard_report_${new Date().toISOString().slice(0,10)}.pdf`);\n                } catch (e) {\n                    console.error(e); alert(i18n.errorPdf);\n                    cleanupPdfDomState();\n                }\n                btn.innerHTML = originalHTML;\n            };<\/p>\n<p>            const handleExport = (action, btn) => {\n                if (!isGated || localStorage.getItem('dashd_unlocked')) {\n                    action === 'csv' ? execCsv() : execPdf(btn);\n                } else {\n                    pendingAction = action; modal.classList.add('active'); errorDiv.style.display = 'none';\n                }\n            };<\/p>\n<p>            if (isGated && modal) {\n                modal.querySelector('.dashd-modal-close').onclick = () => modal.classList.remove('active');<\/p>\n<p>                submitBtn.onclick = async () => {\n                    const em = emailInput.value.trim(); const hp = hpInput.value.trim();\n                    if (!em || !em.includes('@')) { errorDiv.innerText = i18n.invalidEmail; errorDiv.style.display = 'block'; return; }<\/p>\n<p>                    submitBtn.innerHTML = `<span class=\"dashicons dashicons-update\" style=\"animation: spin 1s linear infinite;\"><\/span> ${escapeHtml(i18n.verifying)}`;\n                    submitBtn.style.opacity = '0.7'; submitBtn.style.pointerEvents = 'none'; errorDiv.style.display = 'none';<\/p>\n<p>                    const fd = new FormData(); fd.append('action', 'dashd_capture_lead'); fd.append('email', em); fd.append('hp', hp); fd.append('type', pendingAction); fd.append('source', config.key); fd.append('nonce', config.leadNonce || '');<\/p>\n<p>                    try {\n                        const res = await fetch(config.ajax, { method: 'POST', body: fd }); const data = await res.json();\n                        if (data.success) {\n                            localStorage.setItem('dashd_unlocked', '1'); modal.classList.remove('active');\n                            pendingAction === 'csv' ? execCsv() : execPdf(root.querySelector('.dashd-export-pdf'));\n                        } else {\n                            errorDiv.innerText = data.data.msg || i18n.errorGeneral; errorDiv.style.display = 'block';\n                        }\n                    } catch(e) {\n                        errorDiv.innerText = i18n.errorServer; errorDiv.style.display = 'block';\n                    }<\/p>\n<p>                    submitBtn.textContent = i18n.unlockAndDownload; submitBtn.style.opacity = '1'; submitBtn.style.pointerEvents = 'auto';\n                };\n            }<\/p>\n<p>            const csvBtn = root.querySelector('.dashd-export-csv'); if(csvBtn) csvBtn.onclick = () => handleExport('csv', csvBtn);\n            const pdfBtn = root.querySelector('.dashd-export-pdf'); if(pdfBtn) pdfBtn.onclick = () => handleExport('pdf', pdfBtn);\n        };<\/p>\n<p>        const updateChartColors = (isDark) => {\n        \tif (typeof Chart === 'undefined') return; \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0449\u0438\u0442\u0443: \u0435\u0441\u043b\u0438 Chart \u0435\u0449\u0435 \u043d\u0435\u0442, \u0432\u044b\u0445\u043e\u0434\u0438\u043c\n            Chart.defaults.color = isDark ? '#94a3b8' : '#666';\n            Chart.defaults.borderColor = isDark ? '#334155' : '#e5e5e5';\n            if (chart) renderChart(); \n        };<\/p>\n<p>            const observer = new MutationObserver((mutations) => {\n                mutations.forEach((mutation) => {\n                    if (mutation.attributeName === 'class') {\n                        if (chart) renderChart(); \n                    }\n                });\n            });<\/p>\n<p>            const init = async () => {\n                showLoader();\n                const bodyEl = document.body;\n                const initialDark = document.documentElement.classList.contains('wp-dark-mode-active') || (bodyEl && bodyEl.classList.contains('wp-dark-mode-active'));\n                updateChartColors(initialDark);<\/p>\n<p>                observer.observe(document.documentElement, { attributes: true });\n                if (bodyEl) {\n                    observer.observe(bodyEl, { attributes: true });\n                }<\/p>\n<p>                let attempts = 0;\n                while (typeof Chart === 'undefined' && attempts < 20) { await new Promise(r => setTimeout(r, 100)); attempts++; }\n                if (typeof Chart === 'undefined') {\n                    console.error('DashD: Chart.js is not available. Widget initialization aborted.');\n                    hideLoader();\n                    return;\n                }<\/p>\n<p>                bindEvents();<\/p>\n<p>                try {\n                    let periodsUrl = `${config.ajax}?action=get_dashd_periods_split&key=${config.key}`;\n                    if (Array.isArray(config.indicatorSpecs) && config.indicatorSpecs.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorSpecs.join(','))}`;\n                    } else if (Array.isArray(config.indicatorIds) && config.indicatorIds.length) {\n                        periodsUrl += `&indicators=${encodeURIComponent(config.indicatorIds.join(','))}`;\n                    }\n                    const pRes = await fetch(periodsUrl);\n                    if (!pRes.ok) throw new Error(`HTTP Error: ${pRes.status}`);<\/p>\n<p>                    const pJson = await pRes.json();<\/p>\n<p>                    if (pJson.success && pJson.data.years.length) {\n                        periodYears = pJson.data.years\n                            .slice()\n                            .sort((a, b) => Number(b) - Number(a))\n                            .map((v) => String(v));\n                        periodQuarters = Array.isArray(pJson.data.quarters) && pJson.data.quarters.length\n                            ? pJson.data.quarters\n                                .slice()\n                                .map((v) => String(v || '').toUpperCase())\n                                .filter((v) => ['Q1', 'Q2', 'Q3', 'Q4'].includes(v))\n                                .sort((a, b) => b.localeCompare(a))\n                            : ['Q4', 'Q3', 'Q2', 'Q1'];\n                        if (!periodQuarters.length) {\n                            periodQuarters = ['Q4', 'Q3', 'Q2', 'Q1'];\n                        }<\/p>\n<p>                        const mapFromApi = (pJson.data.year_quarters && typeof pJson.data.year_quarters === 'object')\n                            ? pJson.data.year_quarters\n                            : {};\n                        periodYearQuarterMap = {};\n                        periodYears.forEach((year) => {\n                            const fromMap = Array.isArray(mapFromApi[year])\n                                ? mapFromApi[year].map((v) => String(v || '').toUpperCase())\n                                : [];\n                            const normalized = periodQuarters.filter((q) => fromMap.includes(q));\n                            periodYearQuarterMap[year] = normalized.length ? normalized : periodQuarters.slice();\n                        });<\/p>\n<p>                        const latestFromApi = pJson.data.latest && typeof pJson.data.latest === 'object'\n                            ? pJson.data.latest\n                            : {};\n                        const latestYear = String(latestFromApi.year || '');\n                        const latestQuarter = String(latestFromApi.quarter || '').toUpperCase();\n                        curY = periodYears.includes(latestYear) ? latestYear : (periodYears[0] || null);\n                        const availableForCurrent = getAvailableQuartersForYear(curY);\n                        curQ = availableForCurrent.includes(latestQuarter)\n                            ? latestQuarter\n                            : (availableForCurrent[0] || periodQuarters[0] || null);\n                        ensureValidQuarterForYear();<\/p>\n<p>                        const yBox = controls.yearButtonsBox;\n                        const qBox = controls.quarterButtonsBox;\n                        if (yBox && qBox) {\n                            yBox.innerHTML = periodYears.map((y) => `<button class=\"dashd-ui-btn ${String(y)===String(curY)?'active-btn':''}\" data-v=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/button>`).join('');\n                            renderQuarterControlsForCurrentYear();<\/p>\n<p>                            yBox.querySelectorAll('button').forEach((b) => {\n                                b.onclick = () => {\n                                    curY = String(b.dataset.v || '');\n                                    if (!curY) return;\n                                    ensureValidQuarterForYear();\n                                    renderQuarterControlsForCurrentYear();\n                                    syncPeriodButtons();\n                                    syncMobileSelectors();\n                                    loadData();\n                                };\n                            });\n                        }<\/p>\n<p>                        if (controls.mobileYearSelect) {\n                            controls.mobileYearSelect.innerHTML = periodYears.map((y) => `<option value=\"${escapeHtml(y)}\">${escapeHtml(y)}<\/option>`).join('');\n                        }\n                        renderQuarterControlsForCurrentYear();\n                        syncPeriodButtons();\n                        syncMobileSelectors();\n                        syncPeriodControlVisibility();\n                        await loadData();\n                    } else { \n                        console.warn(\"DashD: No periods found or API returned success:false\");\n                        hideLoader(); \n                    }\n                } catch (error) {\n                    console.error(\"DashD Network\/Parse Error in init:\", error);\n                    hideLoader(); \n                }\n            };<\/p>\n<p>            const runInit = () => {\n                init().catch((error) => {\n                    console.error('DashD Unexpected init error:', error);\n                    hideLoader();\n                });\n            };<\/p>\n<p>            runInit();\n            root.addEventListener('dashd-reinit', runInit);<\/p>\n<p>            return true;\n        };<\/p>\n<p>        if (!startWidget()) {\n            document.addEventListener('DOMContentLoaded', startWidget, { once: true });\n            window.addEventListener('load', startWidget, { once: true });\n        }\n    })();\n<\/script><\/p>\n<style>\n        @keyframes spin { 100% { transform: rotate(360deg); } }\n    <\/style>\n<p><!--more--><br \/>\n<!-- {\"type\":\"layout\",\"children\":[{\"type\":\"section\",\"props\":{\"css\":\"@media (min-width: 959px) {\\n    .el-section {\\n        margin-top: 6% !important;\\n    }\\n}\",\"height_viewport_offset\":false,\"image_position\":\"center-center\",\"padding_bottom\":\"small\",\"padding_top\":\"none\",\"style\":\"\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"\"},\"children\":[{\"type\":\"row\",\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\"},\"children\":[{\"type\":\"panel-slider\",\"props\":{\"blend\":false,\"content_align\":true,\"content_column_breakpoint\":\"m\",\"content_margin_auto\":false,\"css\":\".uk-slidenav {\\n    border: 0 solid transparent;\\n    color: #999;\\n    gap: 20px;\\n    position: relative;\\n    left: -15vw;\\n    \/*top: 100%; *\/\\n    background-color: #00000010;\\n}\\n\\n\/* 2. \u0426\u0435\u043d\u0442\u0440\u0443\u0454\u043c\u043e \u043b\u0456\u0432\u0443 \u0441\u0442\u0440\u0456\u043b\u043a\u0443 (\u0437\u0441\u0443\u0432\u0430\u0454\u043c\u043e \u0432\u043f\u0440\u0430\u0432\u043e) *\/\\n.el-slidenav.uk-slidenav-previous svg {\\n    transform: translateX(4px) !important;\\n}\\n\\n\/* 3. \u0426\u0435\u043d\u0442\u0440\u0443\u0454\u043c\u043e \u043f\u0440\u0430\u0432\u0443 \u0441\u0442\u0440\u0456\u043b\u043a\u0443 (\u0437\u0441\u0443\u0432\u0430\u0454\u043c\u043e \u0432\u043b\u0456\u0432\u043e) *\/\\n.el-slidenav.uk-slidenav-next svg {\\n    transform: translateX(-4px) !important;\\n}\\n\\n.el-slidenav svg path:last-child {\\n    display: none;\\n}\\n\\n.uk-slidenav:last-child {\\n    margin-left: 10px;\\n}\\n\\n.uk-slidenav:hover {\\n    color: #fff;\\n    background-color: #00000040;\\n}\\n\\n.uk-flex-1\\\\@m {\\n    display: flex;\\n    flex-direction: column;\\n    justify-content: center;\\n}\\n\\n@media(min-width: 960px) {\\n    .el-element {\\n        margin-left: 5%;\\n    }\\n\\n    .el-content {\\n        padding-top: 5%;\\n    }\\n\\n    .el-image {\\n        border-top-left-radius: var(--common-border-radius);\\n        border-bottom-left-radius: var(--common-border-radius);\\n    }\\n}\",\"image_align\":\"right\",\"image_expand\":true,\"image_grid_breakpoint\":\"m\",\"image_grid_width\":\"3-5\",\"image_height\":600,\"image_loading\":true,\"image_svg_color\":\"\",\"image_vertical_align\":true,\"image_width\":1000,\"link_style\":\"default\",\"link_text\":\"Read more\",\"margin_bottom\":\"default\",\"margin_top\":\"small\",\"meta_align\":\"below-title\",\"meta_element\":\"div\",\"meta_style\":\"text-meta\",\"nav\":\"\",\"nav_align\":\"center\",\"nav_breakpoint\":\"s\",\"panel_card_offset\":false,\"panel_image_no_padding\":true,\"panel_match\":true,\"panel_padding\":\"default\",\"position_right\":\"40\",\"show_content\":true,\"show_hover_image\":true,\"show_hover_video\":true,\"show_image\":true,\"show_link\":true,\"show_meta\":true,\"show_title\":true,\"show_video\":true,\"slidenav\":\"bottom-center\",\"slidenav_breakpoint\":\"m\",\"slidenav_hover\":false,\"slidenav_large\":false,\"slidenav_margin\":\"\",\"slidenav_outside_breakpoint\":\"xl\",\"slider_autoplay\":true,\"slider_autoplay_interval\":\"10\",\"slider_autoplay_pause\":true,\"slider_divider\":false,\"slider_gap\":\"default\",\"slider_parallax\":false,\"slider_parallax_target\":\"!.tm-grid-expand>*\",\"slider_sets\":true,\"slider_width\":\"fixed\",\"slider_width_default\":\"1-1\",\"slider_width_medium\":\"\",\"title_align\":\"top\",\"title_element\":\"h3\",\"title_font_family\":\"default\",\"title_grid_breakpoint\":\"m\",\"title_grid_width\":\"1-2\",\"title_hover_style\":\"reset\",\"title_margin_auto\":false,\"title_style\":\"h1\"},\"children\":[{\"type\":\"panel-slider_item\",\"props\":{\"content\":\"\n\n<p>The EU4Business\u2013EBRD Credit Line <br class=\\\"uk-visible@m\\\" \/>supports MSMEs in <strong>Armenia<\/strong>, <strong>Georgia<\/strong>, <br class=\\\"uk-visible@m\\\" \/><strong>Moldova<\/strong> and <strong>Ukraine<\/strong> to invest, grow <br class=\\\"uk-visible@m\\\" \/>and align with EU standards.<\/p>\n\n\",\"image\":\"wp-content\/uploads\/2026\/02\/Small-Town-to-Big-Standards-02.jpg\",\"title\":\"Impact <br class=\\\"uk-visible@m\\\" \/>Dashboard\"}},{\"type\":\"panel-slider_item\",\"props\":{\"content\":\"\n\n<p>The EU4Business\u2013EBRD Credit Line <br class=\\\"uk-visible@m\\\" \/>supports MSMEs in <strong>Armenia<\/strong>, <strong>Georgia<\/strong>, <br class=\\\"uk-visible@m\\\" \/><strong>Moldova<\/strong> and <strong>Ukraine<\/strong> to invest, grow <br class=\\\"uk-visible@m\\\" \/>and align with EU standards.<\/p>\n\n\",\"image\":\"wp-content\/uploads\/2026\/02\/\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f_viber_2026-02-06_12-29-42-268.jpg\",\"title\":\"Impact <br class=\\\"uk-visible@m\\\" \/>Dashboard\"}}]}]}]}]},{\"type\":\"section\",\"props\":{\"image_position\":\"center-center\",\"padding_bottom\":\"none\",\"style\":\"default\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"default\"},\"children\":[{\"type\":\"row\",\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\"},\"children\":[{\"type\":\"grid\",\"props\":{\"block_align\":\"center\",\"content_column_breakpoint\":\"m\",\"css\":\"#explore-child {\\n    --wss-margin: 25px;\\n    background-color: #eee;\\n    padding: var(--wss-margin);\\n    border-radius: 30px;\\n}\\n\\n@media (min-width:959px) {\\n    #explore-child {\\n        position: relative;\\n        left: calc(var(--wss-margin) * -1);\\n        top: calc(var(--wss-margin) * -1);\\n        padding: var(--wss-margin);\\n        margin-right: calc(var(--wss-margin) * -2);\\n    }\\n}\",\"filter_align\":\"left\",\"filter_all\":true,\"filter_grid_breakpoint\":\"m\",\"filter_grid_width\":\"auto\",\"filter_position\":\"top\",\"filter_style\":\"tab\",\"grid_column_gap\":\"large\",\"grid_default\":\"1\",\"grid_medium\":\"2\",\"grid_row_gap\":\"large\",\"image_align\":\"left\",\"image_box_decoration_inverse\":false,\"image_expand\":false,\"image_grid_breakpoint\":\"m\",\"image_grid_column_gap\":\"medium\",\"image_grid_width\":\"auto\",\"image_height\":50,\"image_hover_box_shadow\":\"large\",\"image_link\":false,\"image_loading\":true,\"image_svg_animate\":true,\"image_svg_color\":\"\",\"image_svg_inline\":false,\"image_transition\":\"scale-up\",\"image_transition_border\":false,\"image_vertical_align\":false,\"item_animation\":true,\"item_maxwidth\":\"xlarge\",\"lightbox_bg_close\":true,\"link_style\":\"default\",\"link_text\":\"Read more\",\"margin_bottom\":\"default\",\"margin_top\":\"default\",\"meta_align\":\"below-title\",\"meta_element\":\"div\",\"meta_style\":\"text-meta\",\"show_content\":true,\"show_hover_image\":true,\"show_hover_video\":true,\"show_image\":true,\"show_link\":true,\"show_meta\":true,\"show_title\":false,\"show_video\":true,\"text_align\":\"left\",\"text_align_breakpoint\":\"m\",\"text_align_fallback\":\"center\",\"title_align\":\"top\",\"title_element\":\"h3\",\"title_grid_breakpoint\":\"m\",\"title_grid_width\":\"1-2\",\"title_hover_style\":\"reset\"},\"children\":[{\"type\":\"grid_item\",\"props\":{\"content\":\"This interactive dashboard presents the Programme\u2019s cumulative results across all participating countries \u2014 from financing volumes and supported businesses to energy savings, emissions reductions and jobs sustained\",\"image\":\"wp-content\/uploads\/2026\/05\/Icon-5-color.svg\",\"title\":\"item 1\"}},{\"type\":\"grid_item\",\"props\":{\"content\":\"Updated quarterly, it provides a transparent view of how EU-backed finance translates into tangible economic and environmental impact across the region\",\"image\":\"wp-content\/uploads\/2026\/05\/Icon-3-color.svg\",\"title\":\"item 1\"}},{\"type\":\"grid_item\",\"props\":{\"content\":\"Explore regional results or apply filters to see how the programme is delivering change where it matters most\",\"image\":\"wp-content\/uploads\/2026\/05\/Icon-4-color.svg\",\"title\":\"item 1\"}},{\"type\":\"grid_item\",\"props\":{\"content\":\"\n\n<h4>Exploring the data<\/h4>\n\n\\n\n\n<p>Use the filter to explore programme results by Country. Charts update dynamically based on the selected filters.<\/p>\n\n\",\"id\":\"explore-child\",\"image\":\"wp-content\/uploads\/2026\/05\/Icon-2-color.svg\",\"title\":\"item 1\"}}]}]}]}]},{\"type\":\"section\",\"props\":{\"image_position\":\"center-center\",\"style\":\"default\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"default\"},\"children\":[{\"type\":\"row\",\"props\":{\"layout\":\"1-5,4-5\"},\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\",\"width_medium\":\"1-4\"},\"children\":[{\"type\":\"headline\",\"props\":{\"content\":\"Understanding <br class=\\\"uk-visible@m\\\" \/>the impact\",\"image_align\":\"left\",\"image_margin\":\"xsmall\",\"text_align\":\"left\",\"text_align_breakpoint\":\"m\",\"text_align_fallback\":\"center\",\"title_element\":\"h3\",\"title_font_family\":\"secondary\",\"title_style\":\"h3\"}}]},{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\",\"width_medium\":\"expand\"},\"children\":[{\"type\":\"text\",\"props\":{\"column_breakpoint\":\"m\",\"content\":\"Programme results are calculated using verified project data and standard methodologies applied across the Programme. Energy savings and emissions reductions are derived from efficiency improvements and renewable energy investments implemented by supported businesses\",\"margin_bottom\":\"default\",\"margin_top\":\"default\",\"text_align\":\"left\",\"text_align_breakpoint\":\"m\",\"text_align_fallback\":\"center\"}}]}]}]},{\"type\":\"section\",\"props\":{\"image_position\":\"center-center\",\"padding_bottom\":\"none\",\"style\":\"muted\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"default\"},\"children\":[{\"type\":\"row\",\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\"},\"children\":[{\"type\":\"headline\",\"props\":{\"content\":\"Financial Indicators\",\"image_align\":\"left\",\"image_margin\":\"xsmall\",\"title_element\":\"h1\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"vertical\",\"bar_stacked\":true,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table1:1\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"horizontal\",\"bar_stacked\":false,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table1:2\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}}]}]}]},{\"type\":\"section\",\"props\":{\"image_position\":\"center-center\",\"padding_bottom\":\"none\",\"padding_top\":\"small\",\"style\":\"default\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"default\"},\"children\":[{\"type\":\"row\",\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\"},\"children\":[{\"type\":\"headline\",\"props\":{\"content\":\"Indicators\",\"image_align\":\"left\",\"image_margin\":\"xsmall\",\"title_element\":\"h1\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"vertical\",\"bar_stacked\":true,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table2:3\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"horizontal\",\"bar_stacked\":false,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table2:4\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"vertical\",\"bar_stacked\":true,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table2:5\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}}]}]}]},{\"type\":\"section\",\"props\":{\"image_position\":\"center-center\",\"padding_top\":\"small\",\"style\":\"muted\",\"title_breakpoint\":\"xl\",\"title_position\":\"top-left\",\"title_rotation\":\"left\",\"vertical_align\":\"middle\",\"width\":\"default\"},\"children\":[{\"type\":\"row\",\"children\":[{\"type\":\"column\",\"props\":{\"image_position\":\"center-center\",\"position_sticky_breakpoint\":\"m\"},\"children\":[{\"type\":\"headline\",\"props\":{\"content\":\"Energy Indicators\",\"image_align\":\"left\",\"image_margin\":\"xsmall\",\"title_element\":\"h1\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"horizontal\",\"bar_stacked\":false,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table3:6\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}},{\"type\":\"dashd_widget\",\"props\":{\"bar_orientation\":\"vertical\",\"bar_stacked\":true,\"colors\":\"#336DFF, #AF9BE2, #3B82F6, #BEE00F, #7FD3F7\",\"colors_custom\":\"\",\"country_order\":\"Ukraine, Armenia, Georgia, Moldova\",\"custom_color_1\":\"\",\"custom_color_2\":\"\",\"custom_color_3\":\"\",\"custom_color_4\":\"\",\"custom_color_5\":\"\",\"gated\":false,\"indicators\":[\"table3:7\"],\"mode\":\"bar\",\"scale\":\"linear\",\"show_periods\":false,\"show_scale_toggle\":false,\"show_view_toggle\":false,\"table\":\"\"}}]}]}]}],\"version\":\"5.0.37\"} --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. item 1 This interactive dashboard presents the Programme\u2019s cumulative results across [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"pgc_sgb_lightbox_settings":"","footnotes":""},"class_list":["post-9031","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE<\/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:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/\" \/>\n<meta property=\"og:locale\" content=\"uk_UA\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE\" \/>\n<meta property=\"og:description\" content=\"Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. item 1 This interactive dashboard presents the Programme\u2019s cumulative results across [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/\" \/>\n<meta property=\"og:site_name\" content=\"EU4BUSINESS EBRD CREDITLINE - UKRAINE\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-26T19:49:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u041f\u0440\u0438\u0431\u043b. \u0447\u0430\u0441 \u0447\u0438\u0442\u0430\u043d\u043d\u044f\" \/>\n\t<meta name=\"twitter:data1\" content=\"5 \u0445\u0432\u0438\u043b\u0438\u043d\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/\",\"url\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/\",\"name\":\"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/sites\\\/2\\\/2026\\\/03\\\/eu4business-ebrd-scaled.webp\",\"datePublished\":\"2026-01-28T21:15:50+00:00\",\"dateModified\":\"2026-07-26T19:49:59+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/#breadcrumb\"},\"inLanguage\":\"uk\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"uk\",\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/sites\\\/2\\\/2026\\\/03\\\/eu4business-ebrd-scaled.webp\",\"contentUrl\":\"https:\\\/\\\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/sites\\\/2\\\/2026\\\/03\\\/eu4business-ebrd-scaled.webp\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/dashboard\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/#website\",\"url\":\"https:\\\/\\\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/\",\"name\":\"EU4BUSINESS EBRD CREDITLINE - UKRAINE\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\\\/uk\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"uk\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE","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:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/","og_locale":"uk_UA","og_type":"article","og_title":"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE","og_description":"Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. Impact Dashboard The EU4Business\u2013EBRD Credit Line supports MSMEs in Armenia, Georgia, Moldova and Ukraine to invest, grow and align with EU standards. item 1 This interactive dashboard presents the Programme\u2019s cumulative results across [&hellip;]","og_url":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/","og_site_name":"EU4BUSINESS EBRD CREDITLINE - UKRAINE","article_modified_time":"2026-07-26T19:49:59+00:00","og_image":[{"url":"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"\u041f\u0440\u0438\u0431\u043b. \u0447\u0430\u0441 \u0447\u0438\u0442\u0430\u043d\u043d\u044f":"5 \u0445\u0432\u0438\u043b\u0438\u043d"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/","url":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/","name":"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c - EU4BUSINESS EBRD CREDITLINE - UKRAINE","isPartOf":{"@id":"https:\/\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/#primaryimage"},"image":{"@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/#primaryimage"},"thumbnailUrl":"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp","datePublished":"2026-01-28T21:15:50+00:00","dateModified":"2026-07-26T19:49:59+00:00","breadcrumb":{"@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/#breadcrumb"},"inLanguage":"uk","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/"]}]},{"@type":"ImageObject","inLanguage":"uk","@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/#primaryimage","url":"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp","contentUrl":"https:\/\/ukraine.ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/wp-content\/uploads\/sites\/2\/sites\/2\/2026\/03\/eu4business-ebrd-scaled.webp"},{"@type":"BreadcrumbList","@id":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/dashboard\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/"},{"@type":"ListItem","position":2,"name":"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0439\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c"}]},{"@type":"WebSite","@id":"https:\/\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/#website","url":"https:\/\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/","name":"EU4BUSINESS EBRD CREDITLINE - UKRAINE","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ukraine.ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"uk"}]}},"_links":{"self":[{"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/pages\/9031","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/comments?post=9031"}],"version-history":[{"count":1,"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/pages\/9031\/revisions"}],"predecessor-version":[{"id":9032,"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/pages\/9031\/revisions\/9032"}],"wp:attachment":[{"href":"https:\/\/ukraine.eu4business-ebrdcreditline.wss-develope.uk\/uk\/wp-json\/wp\/v2\/media?parent=9031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}